This is an old note about timers in .NET that might be interesting to someone. I believe the same concept could be applied in other programming languages.
As noted by Joe Albahari in his article about timers (http://www.albahari.com/threading/part3.aspx#_Timers), they provide a more effective way to manage memory and resources compared to an approach where we create a thread containing code like this:
volatile static bool keepGoing = true;
while (keepGoing)
{
// do something if something bad occurred somewhere in code
keepGoing = false;
}
The same idea is described by Jeffrey Richter in his CLR via C# book (take a look at the chapter “Performing a Periodic Compute-Bound Operationâ€).
What does this mean? With an infinite loop, you can encounter issues such as resource leaks and other problems. By using timers, once a thread finishes its work, it frees any resources you may have forgotten to release, and a new thread is created to perform the same task again.
A common example that comes to mind is a WPF application with a separate thread that should periodically monitor something or repeat a sequence of actions.
Of course, we should not forget about handling errors and implementing cancellation in our threads, which makes the work more complex.
Let’s return to the topic of timers and take a closer look at them.
There are four types of timers:
- General-purpose multithreading timers
- Special-purpose single-threaded timers
The first group of timers includes the following classes:
System.Threading.Timer
System.Timers.Timer
Both of these use the thread pool, and System.Timers.Timer
is a wrapper around System.Threading.Timer
. Below is a simple console application that demonstrates how System.Threading.Timer
works:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace ConsoleApplication4 {
class Program {
static void Main(string[] args) {
Timer t = new Timer(testDelegate,null, 0, 250);
Console.ReadLine();
}
static void testDelegate(object obj) {
System.Diagnostics.Trace.WriteLine("call to testDelegate, thread id: "
+ Thread.CurrentThread.ManagedThreadId + " , is tp: " + Thread.CurrentThread.IsThreadPoolThread);
}
}
}
The trace output of the execution will be something like the one shown below:

As you can see, testDelegate
is called on different threads from the thread pool. As a result:
- We can’t directly change UI elements from WPF or Windows Forms in the timer’s handler using these types of timers (since
System.Timers.Timer
also uses the thread pool) without employing a synchronization mechanism. - We need to ensure that the timer’s handler (delegate) is written in a thread-safe manner because a new event could be triggered before the previous one has finished.
I recommend you take a look at source code of .NET System.Threading.Timer – https://referencesource.microsoft.com/#mscorlib/system/threading/timer.cs. to get detailed information about how Timer class work. In brief:
- there is only one queue (class TimerQueue) in the AppDomain realized as singleton pattern that maintains all active timers (class TimerQueueTimer). Queue is realized as an unordered doubly-linked list due needing of good performance for inserting and deleting operations
- each time we create new timer it is added to the queue
- AppDomainTimerCallback is called by VM when the native timer fires. I think native timer is some kernel object that can be accessed trough Win API and used to provide all necessary functionality to managed code
- AppDomainTimerCallback calls FireNextTimers method that walks trough linked list gets timer object (TimerQueueTimer) and checks if is there need to call to Fire method. It gives the first available timer object and fires on this thread (timerToFireOnThisThread.Fire()). Other timers will be added to the thread pool (QueueTimerCompletion(timer))
- Fire method is just wrapper under CallCallback method which executes our timer’s handler (to which point m_timerCallback).
And here is source code of System.Timers.Timer – https://referencesource.microsoft.com/#System/services/timers/system/timers/Timer.cs
Here is the place in the code where the timer
member will be set by the value of the System.Threading.Timer
object:
csharpCopy codetimer = new System.Threading.Timer(callback, cookie, i, autoReset ? i : Timeout.Infinite);
System.Timers.Timer
provides additional functionality, which is described here: Joe Albahari’s Timers Article and on MSDN. Interestingly, Jeffrey Richter doesn't recommend using this class, as it likely should have been removed.
The second group of timers is designed to simplify working with timers in WPF and Windows Forms applications:
System.Windows.Threading.DispatcherTimer
(WPF)System.Windows.Forms.Timer
(Windows Forms)
These are quite similar to System.Timers.Timer
in terms of their members, but instead of using the thread pool, they rely on a message-pumping approach. As a result, the timer’s handler code is executed on the same thread as the UI code. A disadvantage of this approach is the inability to run long-running code in the handler without blocking the UI thread, which can lead to freezing the user interface.
After a brief analysis of timers, let’s return to our goal — replacing a thread with an infinite loop with a timer’s handler that is periodically called by the timer. Below is a simple WPF application with a bug.
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e) {
Timer timer = new Timer(testTimerCode, null, 0, 3000);
}
private static void testTimerCode(object obj) {
System.Diagnostics.Trace.WriteLine("test timer tick");
}
}
As shown below timer’s handler will be called only 2 times

The reason is that when the timer
variable becomes unreachable, the garbage collector stops the timer.
This code implements it in correct way (we use static variable that holds our timer intead)
public partial class MainWindow : Window {
private static Timer timer; public MainWindow() {
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e) {
StartTest.IsEnabled = false;
timer = new Timer(testTimerCode, null, 0, 3000);
}
private static void testTimerCode(object obj) {
System.Diagnostics.Trace.WriteLine("test timer tick");
}
}
This timer works until you stop it. Another issue with System.Threading.Timer
is that it can be triggered multiple times, which means two or more threads could execute the timer’s callback handler simultaneously. This problem is illustrated in the example below:
public partial class MainWindow : Window {
private static Timer timer; public MainWindow() {
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e) {
StartTest.IsEnabled = false;
timer = new Timer(testTimerCode, null, 0, 3);
}
private static void testTimerCode(object obj) {
System.Diagnostics.Trace.WriteLine("test timer tick, " +
Thread.CurrentThread.ManagedThreadId); Thread.Sleep(2000);
}
}
A result of execution is the following

Because the testTimerCode
is now executing for a longer duration, the timer triggers new threads more frequently, causing multiple thread pool threads to execute simultaneously. A great workaround for this issue is described in Jeffry’s book:
public partial class MainWindow : Window {
private static Timer timer;
public MainWindow() {
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e) {
StartTest.IsEnabled = false;
timer = new Timer(testTimerCode, null, Timeout.Infinite, Timeout.Infinite);
timer.Change(0, Timeout.Infinite);
}
private static void testTimerCode(object obj) {
System.Diagnostics.Trace.WriteLine("test timer tick, " +
Thread.CurrentThread.ManagedThreadId);
// simulate time-consuming work
Thread.Sleep(2000);
timer.Change(3000, Timeout.Infinite);
}
}
timer.Change(0, Timeout.Infinite); – starts the timer immediately (due time = 0) but ensures it doesn’t repeat (interval = Timeout.Infinite) thus it will be executed at least once. Then in
timer.Change(3000, Timeout.Infinite); – sets the timer to fire again after 3000 milliseconds (3 seconds) and ensures it doesn’t repeat automatically (Timeout.Infinite).
So, if you need to run some task every 5 minuets for example, just change first argument of Change method in testTimerCode handler as shown below:
timer.Change(5 * 60 * 1000, Timeout.Infinite);
Now we see that the current thread finishes, and then a new one starts again.
