Thread
s and Timer
s are the most common things that you need for your application. Any work that needs to be done in background without intervening the work that is running in the foreground needed to be done using a Thread
. We create Thread
s to delegate a long running process in background so that the UI remains unblocked. Timer
s on the other hand are a special module which runs after a certain interval of time in background. So you would think Timer
s will also create a new Thread
in background and run the module associated with it after a certain time. This is not always true.
In this post, I will compare most of the timers available with .NET right now, and later on discuss about DispatcherTimer
in WPF.
Difference between Concurrency and Asynchrony?
Now, if you look back when Microsoft introduced async CTP in PDC 2010, or my own article on Async, it is clearly stated that Asynchrony and Concurrency are two different concepts. Asynchrony means running a job without blocking the Thread
where it is working at. Concurrency is actually a special kind of asynchrony where it is achieved by creating a new Thread
. Hence you can say, all sorts of concurrency is asynchrony while all asynchrony is not concurrency. You can have asynchrony without concurrency and it is really worth doing that, as you all know it is not good to put every work in a separate thread. ThreadPool
s could somewhat help by allowing you to manage threads but still Threads are for long running background processes, so beware to use it only when you absolutely require it.
Going ahead with this thought, let's compare the existing Timer
s.There are a number of Timer
s available with .NET before. Many of us might not know what is the basic difference between them. Let's put a comparative analysis on them one by one.
Comparison of Timers (Backtracking Thoughts)
System.Windows.Forms.Timer
Well, if you have ever worked in Windows based application in .NET, this object must be very well known to you. Windows.Forms.Timer
is actually a normal Windows object which sends the messages directly to the Window messages which runs in background when no other foreground work is running. Hence, the Timer tick event is actually invoked directly into the UI thread and will invoke the EventHandler
that we pass to it when the UI Thread is idle and processing window messages.
The Usage
private System.Windows.Forms.Timer WinTimer = new System.Windows.Forms.Timer();
ObservableCollection<string> WinTimerList = new ObservableCollection<string>();
private void btnwft_Click(object sender, RoutedEventArgs e)
{
this.WinTimer.Interval = 1000;
this.WinTimer.Tick += new EventHandler(WinTimer_Tick);
this.WinTimer.Start();
this.WinTimerList.Clear();
this.lstwft.DataContext = this.WinTimerList;
}
void WinTimer_Tick(object sender, EventArgs e)
{
this.WinTimerList.Add(string.Format("Tick Generated from {0}",
Thread.CurrentThread.Name));
}
So basically, the object timer has a well defined structure, which calls an event Tick
after a certain time interval (in milliseconds).
Things to Remember
- Runs in UI
Thread
- Does not generate event when current UI
Thread
is busy - It inserts a Window Message to invoke the method when
Application.DoEvents
occurs. Explicit call to Application.DoEvents
also generates the timer.
System.Timers.Timer
It is a special Timer
that is designed for running in multi-threaded environment and also can be safely accessible from any thread. In fact, this timer safely calls a new thread from the ThreadPool
and uses ISynchronizeInvoke
object to achieve this.
The Timers.Timer
is also capable of calling itself in a thread which you specify. It exposes SynchronizingObject
which needs an object of ISyncrhonizeInvoke
. As window forms objects are itself implemented from ISynchronizeInvoke
, it can be attached easily with UI Thread
s. Thus by setting the ISynchronizeObject
to window, will automatically call the Timer
callback in the UI thread. Strangely, WPF does not support ISynchronizeInvoke
, hence you need to create one yourself if you want to use it for WPF.
Usage
private System.Timers.Timer TTTimer = new System.Timers.Timer();
ObservableCollection<string> TTimerList = new ObservableCollection<string>();
private void btntt_Click(object sender, RoutedEventArgs e)
{
this.TTTimer.Interval = 1000;
this.TTTimer.Elapsed += new System.Timers.ElapsedEventHandler(TTTimer_Elapsed);
this.TTTimer.Start();
this.TTimerList.Clear();
this.lsttt.DataContext = this.TTimerList;
}
void TTTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
string message = string.Format("Tick Generated from {0}", Thread.CurrentThread.Name);
this.Dispatcher.Invoke((Action)delegate()
{
this.TTimerList.Add(message);
});
}
So, you can see the interface is almost the same, while instead of normal EventHandler
the Timers.Timer
actually passes an ElapsedEventHandler
.
Even though this can be assigned to UI Thread using ISynchronizeInvoke
, yet one major difference with Forms.Timer
is that it will always queue a message on every timer interval elapsed even though the UI thread is busy. Hence if for 2 seconds you put a Thread.Sleep
statement on both the timers, the Timers.Timer
will be called twice after 2 seconds, while the Forms.Timer
will queue only once.
Things to Remember
- It invokes the available thread in
ThreadPool
to run the interface ThreadSafe
, each eventhandler has explicit locks- Can be run in any thread using
ISynchronizeObject
The Internal
If you try to see the implementation detail of the Timer
, you will see that the Timer
actually puts an AutoResetEvent
hooked with the Time
for the next call. It invokes the callback using ISynchronizeObject.BeginInvoke
. As Begin
patterns actually creates a Thread
from ThreadPool
, it always uses a ThreadPool
by default.
The Timer
uses ChangeTimerNative
to change time and gets the elapsed callback from AddTimeNative
calls.
System.Threading.Timer
This Timer
is actually widely used and creates a new Thread
inside it to run the callback. The Threading.Timer
class is not ThreadSafe
. So you should always device your code if you need ThreadSafe
access of objects. Even, the class is not well structured and user friendly. It needs every input in its constructor to call a thread. As it always runs on a new Thread
from ThreadPool
, you should not use it extensively as because even your UI Thread remains idle, it still waits to find other background Thread
s for its execution.
Usage
private System.Threading.Timer STTimer;
ObservableCollection<string> STimerList = new ObservableCollection<string>();
private void btnstt_Click(object sender, RoutedEventArgs e)
{
this.STTimer = new Timer(this.TimerElapsed, null, 1000,
System.Threading.Timeout.Infinite);
this.STimerList.Clear();
this.lststt.DataContext = this.STimerList;
}
void TimerElapsed(object state)
{
string message = string.Format("Tick Generated from {0}", Thread.CurrentThread.Name);
this.Dispatcher.Invoke((Action)delegate()
{
this.STimerList.Add(message);
});
}
Hence the constructor for Timer
needs the callback method. The 2nd parameter is the state, which will be received to the callback. 3rd parameter represents the time after which the call will take place. 1000 means after 1 second the timer will invoke the Callback. TimeOut
represents the periods, specify any numeric integers. 0
and Invinite
will remove the subsequent calls to the method.
Like System.Timers.Timer
, it also uses AddTimerNative
call to get events from native environment. But it does always invoke the object in a new thread.
Things to Remember
- Runs in a new thread always
- Explicit call to period is required
- You can use the
Change
method to change the properties after the Timer
is invoked - Class does not support inheritance
- Purely used for numerical timing, where UI update is not or very less required.
DispatcherTimer
In WPF, the most common Timer
that we use is DispatcherTimer
. It runs on the Dispatcher Thread
by default (UI Thread) and invokes the callback based on DispatcherPriority
. DispatcherTimer
is a special Timing
object for WPF just like Forms.Timer
in Windows. Dispatcher
timer is not restricted to only one thread, but rather runs every event on Dispatcher
thread. If you are not aware of Dispatcher
, you might want to read my WPF Tutorial series. DispatcherPriority
is very useful when dealing with DispatcherTimer
. The Threading model identifies the Priority of the Dispatcher callback and treats it accordingly.
DispatcherPriority
- Inactive - throws an exception
- SystemIdle - called when
System
is Idle or SystemIdle
process takes maximum CPU time - ApplicationIdle - Processes when Application is idle means UI thread is free
- ContextIdle - Processed when background operation is complete
- Background - Processed in background means processed only when all other non-idle operations are complete
- Send- Highest, and sent immediately
There are other priorities too, which might be used.
Usage
DispatcherTimer dispTimer = new DispatcherTimer(DispatcherPriority.SystemIdle);
ObservableCollection<string> stDispatcher = new ObservableCollection<string>();
private void btnDispatcher_Click(object sender, RoutedEventArgs e)
{
dispTimer.Interval = TimeSpan.FromSeconds(1);
dispTimer.Tick += new EventHandler(dispTimer_Tick);
dispTimer.IsEnabled = true;
stDispatcher.Clear();
this.lstDispatcher.DataContext = stDispatcher;
}
void dispTimer_Tick(object sender, EventArgs e)
{
this.stDispatcher.Add(string.Format("Tick Generated from {0}",
Thread.CurrentThread.Name));
}
Now this will ensure that the dispTimer
will be called after 1 second, and require the System
to be Idle
. If you are running complex operations, the Timer
will not be called. Hence this gives you a chance to ensure that the timer will be called only when all other foreground operation is complete. Instead of that, if you specify DispatcherPriority.Send
, it will be immediately processed.
The DispatcherTimer
is elapsed on the Dispatcher Thread
, and hence it is safe to use for any WPF applications.
The Internals
If you see the internals of the DispatcherTimer
, you will eventually find that the DispatcherTimer
is also using the same native API to call the eventhandler
. But the only difference is that it uses DispatcherThread
to process the code.
The hooks lets us specify the various DispatcherEvents
and allows it to Raise Timer
event based on situation of the Dispatcher
.
You should note that DispatcherTimer
is ThreadSafe
.
Conclusion
In this brief case study, I think you might be clear about the usage of different timers. I hope to find feedback. Feel free to write.
Thank you for reading.