Stopping and starting a System.Timers.Timer - be careful you don't stop forever!

The timer went pop and nothing else will ever happen now

I've sometimes seen code that stops and starts a timer during its TimerElapsed event in order to ensure that the event isn't called whilst it's still being executed from a previous call. If this isn't done then you can end up with multiple instances of the handler running concurrently which is likely not what you want to happen. Now, according to the documentation:

The Timer component catches and suppresses all exceptions thrown by event handlers for the Elapsed event. This behavior is subject to change in future releases of the .NET Framework.

This holds absolutely true if your event handler looks like this:

private static void TimerElapsed(object sender, ElapsedEventArgs e)
{
    Console.WriteLine($"{DateTime.Now.ToLongTimeString()}: Timer Elapsed - Counter: {counter}");
    _timer.Stop();
    DoTheRealWork();
    _timer.Start();
}

And you'll end up getting output that looks something like this:

The timer class handling and hiding exceptions thrown by the handler

However, if it looks like this:

private static void TimerElapsed(object sender, ElapsedEventArgs e)
{
    Console.WriteLine($"{DateTime.Now.ToLongTimeString()}: Timer Elapsed - Counter: {counter}");
    _timer.Stop();
    var task = Task.Run(() => DoTheRealWork());
    task.Wait();
    _timer.Start();
}

Then you need to make sure your DoTheRealWork method is handling all of its exceptions otherwise you'll instead see something like this:

The trouble with Tasks....

The behaviour when there's Task.Run/Task.Wait in the mix seems to be counter to the documentation with an exception being thrown that doesn't get swallowed by the Timer component. The documentation does say "This behavior is subject to change in future releases of the .NET Framework" so even now, without Tasks in the mix it's best not to rely on the Timer to handle any exceptions for you.

About Rob

I've been interested in computing since the day my Dad purchased his first business PC (an Amstrad PC 1640 for anyone interested) which introduced me to MS-DOS batch programming and BASIC.

My skillset has matured somewhat since then, which you'll probably see from the posts here. You can read a bit more about me on the about page of the site, or check out some of the other posts on my areas of interest.

No Comments

Add a Comment