How to raise only 1 Timer event in C#? - c#

How do I get a timer event to fire one at a time.
For example I have a timer that raises an event every 10 minutes.
The event that is raised takes 10 or more minutes to finish executing.
I would like the timer to reset AFTER the event has finished.
In other words I do not want to raise more than 1 instance of the event at any one time.

Use System.Timers.Timer not the Threading one
Set AutoReset to false.
Then Start it again when you're done.

Usually what I do is have my event stop the timer when it's raised and then restart the timer when the event process completes:
private void timerHandler(object sender, TimerElapsedEventArgs e)
{
Timer timer = (Timer)sender;
timer.Stop();
RunProcess();
timer.Start();
}
public void RunProcess()
{
/* Do stuff that takes longer than my timer interval */
}
Now my timer will start again on completion of the process

It may be difficult to stop timers for efficiency or logic. The following code synchronizes skipping the events.
static readonly object key = new object();
void TimerHandler(object sender, TimerElapsedEventArgs e)
{
if(Monitor.TryEnter(key))
{
try
{
//do your stuff
}
finally
{
Montitor.Exit(key);
}
}
}

Related

Print something to console after x milliseconds

I'm trying to figure out how to make it so, after lets say, 1 minute so 60000 milliseconds the console will say hi.
All I have so far is
System.Timers.Timer timer = new System.Timers.Timer(60000);
timer.Start();
But I don't know how to make it so when the timer is done, it will do something.
You can use the elapse event, when 60000 ms has pass the event will be thrown. Example of the elapse event:
class Program
{
static void Main(string[] args)
{
System.Timers.Timer timer = new System.Timers.Timer(60000);
timer.Elapsed += new System.Timers.ElapsedEventHandler(elapse); // subscribing to the elapse event
timer.Start(); // start Timer
Console.ReadLine(); // hold compiler until key pressed
}
private static void elapse(object sender, ElapsedEventArgs e)
{
Console.WriteLine("Hy");
}
}
or
void Main()
{
var t = new System.Threading.Timer((s)=>Console.WriteLine("Hi"),null,0,60000);
Console.ReadLine();
}
You can use System.Threading.Thread.Sleep if you only want to do the write once (the timer will run every x seconds):
System.Threading.Thread.Sleep(60000);
Console.WriteLine("something");
What you will want to do is create an event that writes to the console when the timer has elapsed the predefined amount of time.
This is done as follows:
Start by creating your timer and set it to 60s:
var timer = new System.Timers.Timer(60000); //60seconds
Next create an event that will be triggered when the time has elapsed:
private static void MyEvent(object sender, ElapsedEventArgs e)
{
Console.WriteLine("Hello World");
}
Next, bind the timer to that event:
timer.Elapsed += MyEvent;
What this does is tell the computer that when the timer actually starts running in the future and then the timer elapses (60s passes after the timer starts), then the Event called 'MyEvent' will be called which writes to the console.
Finally Start the timer:
timer.Start();
And wait for the even to trigger and write to the console.

worker class with timer ensure that method is only invoked once

I am currently using this preliminary approach:
public class AskingForWorkClass
{
private static Timer _timer;
public void Start()
{
// catchup with outstanding work
DoWork(this, null);
_timer = new Timer { Interval = 1000 }; // one second
_timer.Elapsed += DoWork;
_timer.Start();
}
private void DoWork(object sender, EventArgs e)
{
}
}
The intention is that when Start is invoked all outstanding work is done first. After that a timer is used to invoke DoWork, which checks for more work does it. Please note that I would like to prevent DoWork from being hit by the timer if it is still running from the last invocation by the timer. Is this possible? Basically, DoWork should only be run by one process at the time.
You can just start / stop the timer in your DoWork method:
private void DoWork(object sender, EventArgs e)
{
_timer.Stop();
// .. do stuff ...
_timer.Start();
}
Note: depending on which Timer class you're using, you may not have Start and Stop and instead need to use the Modify method, but you get the idea.
UPDATE
So based on comments this is a solution which should prevent any incident of DoWork executing twice, regardless of the Interval property.
public class AskingForWorkClass
{
private static Timer _timer;
private AutoResetEvent _event = new AutoResetEvent(true);
public void Start()
{
// catchup with outstanding work
DoWork(this, null);
_timer = new Timer { Interval = 1000 }; // one second
_timer.Elapsed += DoWork;
_timer.Start();
}
private void DoWork(object sender, EventArgs e)
{
_event.WaitOne();
// ... do stuff here ...
_event.Set();
}
}
What happens here is that that when DoWork is entered it will wait until the event has been set to the signaled state and block the current thread until that happens. Note that the construction of the event new AutoResetEvent(true) creates the event in the signaled state so the first time DoWork is called it doesn't block forever.
Once the WaitOne call passes, the event automatically sets itself back to the unsignaled state meaning that future calls to the DoWork method will be blocked. Then finally we call the Set method which puts the event back into the signaled state until the next WaitOne call.

Is there a way to use one Timer for multiple events?

I am in C# .NET 3.5
What happens when timer elapses and event handler is performed ?
Does the timer cease to exist ?
Can I register several events in different time on one timer, expecting them all to fire one after another ?
You can set a timer to fire off the event only once or continue to do it (Timer.AutoReset property). Yes, you can register several different event handlers on a single timer, but I don't know that there is any way of knowing what order they will fire. If that matters to you, set a single handler, and have that handler call the others. If what you are trying to do is to call a different handler, each time the timer goes off, I would suggest setting a single handler that keeps an enum indicating which function to call and incrementing it each time it gets called by the timer.
To call the same handler to "iterate" through a list of parameters, once on each interval elapsed, I would have an array or list of the parameters and the handler would just increase a counter or consume the list.
using System.Timers;
public class MyTimedDelete {
private static List<int> ListOfIds=null;
private static System.Timers.Timer myTimer=null;
public static void AddIdToQueue(int id)
{
if (ListOfIds == null)
{
ListOfIds = new List<int>();
myTimer = new System.Timers.Timer(2000);
myTimer.Elapsed += OnTimedEvent;
}
ListOfIds.Add(id);
if (ListOfIds.Count==1)
{
myTimer.Start();
}
}
private static void OnTimedEvent(Object source, ElapsedEventArgs e)
{
deleteItem(ListOfIds[0]);
ListOfIds.RemoveAt(0);
if (ListOfIds.Count == 0) {
myTimer.Stop();
}
}
}

Raising a function by timer

I want to raise a function periodically .
When I finish one function cycle to wait some period of time and only them to start the second run.
I thought to make it like :
timer = new System.Timers.Timer();
timer.Interval = 1000;
timer.Enabled = true;
timer.Start();
timer.Elapsed += TimerTick;
private void TimerTick(object sender, EventArgs e)
{
//My functionality
}
But seems that TimerTick is raised every secound and not secound from my last TimerTick run .
How i can solve this one ?
You can use threads:
var thread = new Thread(o => {
while(true)
{
DoTick();
Thread.Sleep(1000);
}
});
You can stop your timer before doing your processing and start it again after it's done:
private void TimerTick(object sender, EventArgs e)
{
timer.Stop();
//My functionality
timer.Start();
}
it's also a good idea to put your functionality in a try-catch and call Start() in the finally section. (if this suits you)
Try the following:
private void TimerTick(object sender, EventArgs e)
{
// get the timer that raised this event (you can have multiple
// timers, or the timer obj is out of scope here, so use this):
Timer timer = (Timer) sender;
// disable (or use timer.Stop())
timer.Enabled = false;
// ...
// your code
// ...
// at end, re-enable
timer.Enabled = true;
}
you will find that the timer will now run 1000ms after your code finished. You can also use timer.Stop() and timer.Start().
you could always do something like this:
while (true)
{
// your functions
Thread.Sleep(1000)
}
you'd have to find a way to stop this through an external mechanism, but it should work.
You're right: the timer will run every second: it won't care what you're doing in the TimerTick.
What you can do is to stop the timer on entering the TimerTick methode.
private void TimerTick(object sender, EventArgs e)
{
timer.Stop();
//My functionality
timer.Start();
}
Try this:
DateTime lastDT = DateTime.MinValue;
private void TimerTick(object sender, EventArgs e)
{
DateTime now = DateTime.Now;
if (now - last).TotalSeconds > what_you_want
{
//My functionality
}
last = now;
}
Using this, your form (main thread) is not locked and you/user can do what you please.
Try
private void TimerTick(object sender, EventArgs e)
{
timer.Stop();
// My Functionality
timer.Stop();
}
However, you may have an extra even fired. As per MSDN Docs:
The signal to raise the Elapsed event is always queued for execution on a ThreadPool thread, so the event-handling method might run on one thread at the same time that a call to the Stop method runs on another thread. This might result in the Elapsed event being raised after the Stop method is called. The code example in the next section shows one way to work around this race condition.
You might want to consider Thread.Sleep() instead

How to block a timer while processing the elapsed event?

I have a timer that needs to not process its elapsed event handler at the same time. But processing one Elapsed event may interfere with others. I implemented the below solution, but something feels wrong; it seems like either I should be using the timer differently or using another object within the threading space. The timer seemed to fit best because I do need to periodically check for a status, but sometimes checking will take longer than my interval. Is this the best way to approach this?
// member variable
private static readonly object timerLock = new object();
private bool found = false;
// elsewhere
timer.Interval = TimeSpan.FromSeconds(5).TotalMilliseconds;
timer.Elapsed = Timer_OnElapsed;
timer.Start();
public void Timer_OnElapsed(object sender, ElapsedEventArgs e)
{
lock(timerLock)
{
if (!found)
{
found = LookForItWhichMightTakeALongTime();
}
}
}
You could set AutoReset to false, then explicitly reset the timer after you are done handling it. Of course, how you handle it really depends on how you expect the timer to operate. Doing it this way would allow your timer to drift away from the actual specified interval (as would stopping and restarting). Your mechanism would allow each interval to fire and be handled but it may result in a backlog of unhandled events that are handled now where near the expiration of the timer that cause the handler to be invoked.
timer.Interval = TimeSpan.FromSeconds(5).TotalMilliseconds;
timer.Elapsed += Timer_OnElapsed;
timer.AutoReset = false;
timer.Start();
public void Timer_OnElapsed(object sender, ElapsedEventArgs e)
{
if (!found)
{
found = LookForItWhichMightTakeALongTime();
}
timer.Start();
}
I usually stop the timer while processing it, enter a try/finally block, and resume the timer when done.
If LookForItWhichMightTakeALongTime() is going to take a long time, I would suggest not using a System.Windows.Forms.Timer because doing so will lock up your UI thread and the user may kill your application thinking that it has frozen.
What you could use is a BackgroundWorker (along with a Timer if so desired).
public class MyForm : Form
{
private BackgroundWorker backgroundWorker = new BackgroundWorker();
public MyForm()
{
InitializeComponents();
backgroundWorker.DoWork += backgroundWorker_DoWork;
backgroundWorker.RunWorkerCompleted +=
backgroundWorker_RunWorkerCompleted;
backgroundWorker.RunWorkerAsync();
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
e.Result = LookForItWhichMightTakeALongTime();
}
private void backgroundWorker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
found = e.Result as MyClass;
}
}
And you can call RunWorkerAsync() from anywhere you want to, even from a Timer if you want. And just make sure to check if the BackgroundWorker is running already since calling RunWorkerAsync() when it's running will throw an exception.
private void timer_Tick(object sender, EventArgs e)
{
if (!backgroundWorker.IsBusy)
backgroundWorker.RunWorkerAsync();
}
timer.enabled = false
or
timer.stop();
and
timer.enabled = true
or
timer.start();
I use the System.Threading.Timer like so
class Class1
{
static Timer timer = new Timer(DoSomething,null,TimeSpan.FromMinutes(1),TimeSpan.FromMinutes(1));
private static void DoSomething(object state)
{
timer = null; // stop timer
// do some long stuff here
timer = new Timer(DoSomething, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
}
}

Categories

Resources