Wednesday, October 27, 2010

Timers for .net Applications

While writing applications for our customers, we find many different options to implement the same functionality. One such situation is when it comes to the use of timer. There are a multitude of timers available in .net. Which one should we use? There might be situations in which using any of them would make no difference but there would definitely be scenarios in which one would make sense to be used. There are many references on the internet discussing the details about each of them. I just want to put some light on their differences and what make them different. This could help you in choosing the best one for your situation.

When we set the Interval of these timers, on the back of our minds, sometimes, we think we want the specified piece of code to be executed after this certain time interval.

Generally, we find four timers used in .net applications. The first two are called Multithreaded timers and the last two are called Single Threaded Timers.

1. System.Timers.Timer
2. System.Threading.Timer
3. System.Windows.Forms.Timer
4. System.Windows.Threading.DispatcherTimer

Three of the four timers described above are named Timer.

System.Timers.Timer:
As MSDN suggests, it is provided to support Server based timer functionality in applications.

The callback is executed on the ThreadPool thread supplied by the system. If we need to use elements on the UI thread in the callback, we need to invoke them using Dispatcher.

In Windows Forms, there might be an alternative approach by using the SynchronizationObject property of this timer. In that case this would be raised on the thread the SynchronizingObject was created. If we set this to a UI object (Window, button or anything else) then this would be raised on UI thread. Basically, whenever the interval elapses, OS reports timer about it and timer calls BeginInvoke on the SynchronizingObject to execute the timer callback. This makes it functionally equivalent of using Single threaded timers [DispatcherTimer or Forms.Timer] as it is using message pumping but it uses that after being invoked from OS [which is different than single threaded timers]. So if UI thread is busy, it keeps on queuing up the callback on the dispatcher. When Dispatcher gets back, it executes them by picking them from the queue in the same order. This is possible for WindowsForms as Control implements ISynchroizeInvoke which can be assigned to SynchronizationObject . This definitely has limitations for software libraries as a hold of UI control is difficult. Keeping this in mind, .net 2.0 introduced SynchronizationContext. So a library might get a hold of SynchronizationContext.Current without being worried about holding a UI object's reference. Basically, it provides virtual methods Send and Post which are inherited by more specialized types for each environments [WindowsFormsSynchronizationContext for Windows Forms and DispatcherSynchronizationContext for WPF]. An instance of this specialized SynchronizationObject is created before the message loop is started. This is used for marshalling for classes like BackgroundWorker (through AsyncOperationManager). So, for WPF application, we can obtain the current instance of SynchronizationContext and post on UI thread. Alternatively, just invoking (Synch or ASynch) using Dispatcher can also be used.

http://msdn.microsoft.com/en-us/magazine/cc163600.aspx

If you still try to assign a WPF element to SynchronizingObject property of Timers.Timer, it results in an exception.



After the lapse of duration specified in Interval, this results in firing of Elapsed event once. If AutoReset is not set, this would not be raised again. By default It is set to true.

This implements a Component based model so we should directly add it to our toolbox. If we drop it on a Window then SynchronizingObject property of this timer should automatically be assigned to the Window. But for WPF, even in VS2010, we can not drag and drop it to the Window. In Windows Forms, if we drop it on a form, it automatically assigns the SynchronizingObject property to the current form. So based on this discussion, it is not very useful for WPF that it inherits from System.ComponentModel.Component.



As discussed above, you will find it disabled like this:



As above, there are other timers too, which implement the same model. We can add all these timers to the Visual Studio Designer toolbox.

System.Windows.Threading.DispatcherTimer:
It seems to be the same thing for WPF as System.Windows.Forms.Timer for Winform applications. The callback is executed on the Dispatcher Queue. Since it is executed on the UI thread, we don't need to use dispatcher to access elements on the UI thread. So no need to write code like this:

this.Dispatcher.BeginInvoke(...)

Being on Dispatcher queue, it is not guaranteed to be executed at the exact interval. If UI thread is busy in some blocking If it is a time critical or real time process, then probably, we should not be using it. It is specially suited for executing any UI behavior at certain interval which, if delayed, does not cause any problems.

This timer allows us to execute some callback after every certain duration. This duration is set by Interval property. The minimum interval allowed is 10 milliseconds.

System.Threading.Timer
This is the second multithreaded timer in .net. The other is System.Timers.Timer. This timer results in running the callback in a separate background thread so there is no event available for subscription. This is a ThreadPool thread provided by the system. This timer is the simplest of all timer with the mini

This is the only timer for which we can specify due time. Due time is basically the time when the timer should start its actual operation even if it is started. So we can have it set so that it starts raising elapsed events each 5 minutes (periodic Interval) but only after 4 hours starting from now. If we just want to execute it once then specify period as 0 (Zero) or Timeout.Infinite. If we want to start timer immediately then specify due time as 0.

System.Windows.Forms.Timer
Those who have come to WPF through Winform background might remember the ClockBox shaped timer control in the ToolBox for Winform designer in Visual Studio. This timer also run in UI thread. So all limitations of DispatcherTimer would be applicable for this timer as well.

As documented by Microsoft, this timer has an accuracy of 55 milliseconds. So, even if, we can set the interval less than 55 ms (upto 1 ms), we might have missed events for this timer.

http://msdn.microsoft.com/en-us/library/system.windows.forms.timer.aspx

MultiThreaded Timer callbacks / handlers after being stopped / disposed:
The callbacks / handlers of multithreaded timers [System.Timers.Timer and System.Threading.Timer] might get executed after them being disposed. This is because they both use ThreadPool timers and it is possible that they are disposed after their callbacks / handlers get queued. Similar logic applies when we stop a thread after its callback is already in ThreadPool Queue.

Following is the display when a timer callback is queued after elapsing the interval.


Now when the timer is stopped / disposed then this callback would still execute by a ThreadPool thread. This might be unexpected for any application. Now let us discuss how we can work around this.

System.Threading.Timer has this amazing overload of Dispose [Dispose(WaitHandle)]. You can find it here [http://msdn.microsoft.com/en-us/library/b97tkt95.aspx]. It waits disposing until all currently queued callbacks have completed execution. After disposing, it signals the WaitHandle passed as argument.

Simultaneous Execution of multiple callback / handlers for multithreaded timers:
Since multithreaded timers use ThreadPool thread, their handlers / callbacks are queued for execution as per the interval settings. It is possible that ThreadPool thread has more than one handlers for same timer in the queue and they are executed simultaneously. This situation should be specially considered as this might lead to an unexpected situation if we don't consider the possibility of re-entrance.



Single Threaded Timer outside Environment:
If we use a single threaded timer in an environment they are not supposed to be used [DispatcherTimer outside WPF or Windows.Forms.Timer outside Winform] then their timers wouldn't be raised. You can be happy with calling Start on the timer but their event handlers wouldn't ever get executed. You might test that by using Winform timer in a WPF application or any of these timers in a Windows Service. This actually makes sense as they use their respective Dispatcher and if one is not available then how can we expect one to work.

Updating Timer Interval:
Since most of these timers (except System.Threading.Timer) has an Interval property, we might want to change it sometime. It must be remembered that updating the interval property during the time when the timer is still running restarts the current interval. So e.g. Interval was set as 5000, the timer is running and 3000 milliseconds are already passed. Now we change the interval to 15000 milliseconds. It must be remembered that the next callback execution would be after 15000 milliseconds after this update. So in total the callback execution after previous one is after 18000 milliseconds.

Single Thread Timer events when UI thread is sleeping:
When UI thread is sleeping then single thread timer events are not generated. So if our UI thread is sleeping for 2 seconds and we have timer interval set as 400 ms then we would miss 5 events. We should be taken this into consideration when using single threaded timers. This is very unlikely scenario because no developer would be causing UI thread to sleep. But if you see missed events then you can consider this possibility.

Timers and Memory Leak:
Keeping external references would not let an object to be garbage collected. This causes memory leak. When we subscribe with Tick / Elapsed event, it seems that it is an internal reference so it shouldn't be causing a memory leak. But it mostly does. I said mostly because it does it for all single and multithreaded timers except System.Threading.Timer.

Basically, there is an external reference in the background. In order to fire the event for timer (Tick / Elapsed), .net framework holds the reference of the timer. This makes GC think that this object should not be collected when it is come across during Garbage Collection.

In order to fix this, we should be using the same universal remedy as we use for all event handlers. Just unsubscribe the timer event in Dispose(). As soon as the event handler is unsubscribed, the framework gets rid of timer reference hence no memory leak. The other solution would be to Dispose() the timer (as timers implement IDiposable themselves).

In the beginning of the memory leak discussion, I told you that MOST of the timers could cause a memory leak. The exception is System.Threading.Timer. As you can guess, there is no event that we subscribe to, in this case. We just need to provide a callback delegate which is run by the runtime after each Interval.

Other Timers:
There are other times too. Let us discuss them briefly:

1. System.Web.UI.Timer
This is used to perform web page postbacks at required intervals. When used as a trigger event for UpdatePanel in AJAX, this causes partial page postbacks of webpage. This is a server timer so you can have server based code in the Tick event. This presents a useful option for implementing financial applications to provide a mechanism to update the page based on certain interval. We can also use it in gaming / sports based web applications where we need to update the scorecards at regular intervals.

2. Multimedia Timer
Multimedia timers have accuracy down to 1 millisecond. This can prove to be the best real time timer that you could have. The issue is that this timer is not available in .net framework so you would have to use native interop for this timer.

You can read further about this timer here:
http://msdn.microsoft.com/en-us/library/system.web.ui.timer.aspx

Which Timer to use
Based on the above discussion, the general idea that you should keep in your mind can be summarized as follows:

1. If more accuracy is needed for the timing of firing the event, then use one of the Timers which do not use UI thread (System.Timers.Timer or System.Threading.Timer).

2. If you need to access elements on UI (like UI controls), it makes more sense to use UI related timers instead (DispatcherTimer or Forms.Timer). Otherwise you need to use Dispatcher to invoke operations on elements on UI thread.

3. If you are worried about re-entrancy of multiple callbacks handlers(simultaneous execution of multiple callbacks). Or if you don't want to handle the scenarios in which timer might be disposed / stopped before executing all waiting callbacks, it would make more sense to use single threaded timers.

No comments: