NoWar
NoWar

Reputation: 37633

Task execution time higher than Timer execution time

I would like to clarify possible code implementaion in case if the code executing withing timerDoJob_Elapsed is getting longer that it should. So all internal things are gonna be coruppted/canceled and etc when timer fires next time.

Is there any pattern for this kind of problem? Any clue about make it more stable?

private void timerDoJob_Elapsed(object sender, ElapsedEventArgs e)
{
     VeryLongTask1();
     VeryLongTask2();
     VeryLongTask3();
}

Upvotes: 0

Views: 70

Answers (2)

Gabriel Luci
Gabriel Luci

Reputation: 40898

If you're using System.Timers.Timer, turn off AutoReset. Then re-enable the timer at the end of your Elapsed method.

private void timerDoJob_Elapsed(object sender, ElapsedEventArgs e)
{
    VeryLongTask1();
    VeryLongTask2();
    VeryLongTask3();
    mytimer.Enabled = true;
}

This way, the timer does not even start again until the task is complete. But make sure to wrap everything in your Elapsed method in try/catch blocks because if an unhandled exception happens there, your timer won't start again.

Another method I've used before is to use a lock in your Elapsed event:

var myLock = new Object();
private void timerDoJob_Elapsed(object sender, ElapsedEventArgs e)
{
    lock (myLock) {
     VeryLongTask1();
     VeryLongTask2();
     VeryLongTask3();
    }
}

This way, two instances of the Elapsed event cannot run at the same time. However, there is a caveat: If the task takes longer than two or more iterations of the timer, then you can have iterations adding up in the background. For example, if your timer elapses after 5 seconds, but your task takes 60 seconds to complete, by the time the first one finishes, you'll have 11 waiting.

Upvotes: 1

Matías Fidemraizer
Matías Fidemraizer

Reputation: 64931

Timer.Change method giving Timeout.Infinite and 0 as arguments will stop the timer (from MSDN):

If dueTime is zero (0), the callback method is invoked immediately. If dueTime is Timeout.Infinite, the callback method is never invoked; the timer is disabled, but can be re-enabled by calling Change and specifying a positive value for dueTime.

One possible and simple but yet powerful approach is stopping the timer until the whole tasks have ended, and then, start the timer again:

private void timerDoJob_Elapsed(object sender, ElapsedEventArgs e)
{
     timerDoJob.Change(Timeout.Infinite, 0);

     // Use a try-finally so if some tasks throws an exception
     // the timer will be re-enabled again anyway
     try
     {
        VeryLongTask1();
        VeryLongTask2();
        VeryLongTask3();
     }
     finally
     {
         timerDoJob.Change(0, 5000);
     }
}

Upvotes: 1

Related Questions