I've a timer object. I want it to be run every minute. Specifically, it should run a OnCallBack
method and gets inactive while a OnCallBack
method is running. Once a OnCallBack
method finishes, it (a OnCallBack
) restarts a timer.
Here is what I have right now:
private static Timer timer; private static void Main() { timer = new Timer(_ => OnCallBack(), null, 0, 1000 * 10); //every 10 seconds Console.ReadLine(); } private static void OnCallBack() { timer.Change(Timeout.Infinite, Timeout.Infinite); //stops the timer Thread.Sleep(3000); //doing some long operation timer.Change(0, 1000 * 10); //restarts the timer }
However, it seems to be not working. It runs very fast every 3 second. Even when if raise a period (1000*10). It seems like it turns a blind eye to 1000 * 10
What did I do wrong?
System. Threading. Timer, which executes a single callback method on a thread pool thread at regular intervals. The callback method is defined when the timer is instantiated and cannot be changed.
No, a timer runs in the thread in which it was created.
Timer is not thread-safe.
If a timer is fired on the main thread's run loop, you will probably have a problem with either the timer function or UI operation. For example, suppose you have triggered a timer. There is also a tableView in your app that shows a list to the user and the user is scrolling the table.
This is not the correct usage of the System.Threading.Timer. When you instantiate the Timer, you should almost always do the following:
_timer = new Timer( Callback, null, TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite );
This will instruct the timer to tick only once when the interval has elapsed. Then in your Callback function you Change the timer once the work has completed, not before. Example:
private void Callback( Object state ) { // Long running operation _timer.Change( TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite ); }
Thus there is no need for locking mechanisms because there is no concurrency. The timer will fire the next callback after the next interval has elapsed + the time of the long running operation.
If you need to run your timer at exactly N milliseconds, then I suggest you measure the time of the long running operation using Stopwatch and then call the Change method appropriately:
private void Callback( Object state ) { Stopwatch watch = new Stopwatch(); watch.Start(); // Long running operation _timer.Change( Math.Max( 0, TIME_INTERVAL_IN_MILLISECONDS - watch.ElapsedMilliseconds ), Timeout.Infinite ); }
I strongly encourage anyone doing .NET and is using the CLR who hasn't read Jeffrey Richter's book - CLR via C#, to read is as soon as possible. Timers and thread pools are explained in great details there.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With