.Net 6 : PeriodTimer

.NET supports various timer classes, each of which offers different functionality. As Microsoft states in its documentation,

  • System.Timers.Timer, which fires an event and executes the code in one or more event sinks at regular intervals. The class is intended for use as a server-based or service component in a multithreaded environment; it has no user interface and is not visible at runtime.
  • 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. Like the System.Timers.Timer class, this class is intended for use as a server-based or service component in a multithreaded environment; it has no user interface and is not visible at runtime.
  • System.Windows.Forms.Timer, a Windows Forms component that fires an event and executes the code in one or more event sinks at regular intervals. The component has no user interface and is designed for use in a single-threaded environment; it executes on the UI thread.
  • System.Web.UI.Timer (.NET Framework only), an ASP.NET component that performs asynchronous or synchronous web page postbacks at a regular interval.
  • System.Windows.Threading.DispatcherTimer, a timer that’s integrated into the Dispatcher queue. This timer is processed with a specified priority at a specified time interval.

In this blog post, we are particularly interested in the System.Threading.Timer. An example of using the System.Threading.Timer is shown in the code snippet below.

int count = 0;
int maxCount = 5;
AutoResetEvent autoEvent = new AutoResetEvent(false);
var timer = new Timer(CallBackMethod, null, 0, 1000);
autoEvent.WaitOne();

void CallBackMethod(object? _)
{
	Console.WriteLine("Hello...");
	Console.WriteLine("World");
	count++;
	if(count== maxCount) autoEvent.Set();
}

The output of the above code is as follows.

Hello...
World
Hello...
World
Hello...
World
Hello...
World
Hello...
World

This looks alright in most cases. But, the moment the execution time of the Callback method exceeds the interval of the timer, the execution overlaps. Let us add a delay between the messages “Hello” and “World” to see the impact.

void CallBackMethod(object? _)
{
	Console.WriteLine("Hello...");
	Thread.Sleep(1000);
	Console.WriteLine("World");
	count++;
	if(count== maxCount) autoEvent.Set();
}

As you can see from the output below, the executions of the callbacks at each intervals has now overlapped with each.

Hello...
Hello...
World
World
Hello...
World
Hello...
World
Hello...
Hello...
World

This might be an undesired scenario in many cases. To achieve this asynchronously using existing set of Timers would need to add more synchronizing structures in the code. Thankfully, .Net 6 has a new Timer which could be used for the purpose PeriodicTimer.

Consider the following code.

var timer = new PeriodicTimer(TimeSpan.FromMilliseconds(1000));
while(await timer.WaitForNextTickAsync())
{
	CallBackMethod(null);
	if (count == maxCount) break;
}

void CallBackMethod(object? _)
{
	Console.WriteLine("Hello...");
	Thread.Sleep(500);
	Console.WriteLine("World");
	count++;
}

The PeriodicTimer would enable us to wait asynchronously for the specified interval. Moreover, the time would be disabled during the execution of the callback. This enables us to avoid the overlap issue which faced in the earlier timers. Additionally, you could also do away with any additional code needed to control the timers as with the code in the earlier part of the post.

That’s another feature that .Net 6 would be bring to us.

Leave a comment