Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Timer behavior when execution takes longer than span?

Tags:

I'm writing windows service which will process "something" every couple minutes.

Here is some code:

public Service()
        {
            this.InitializeComponent();
            this.ServiceName = Name;
            this.CanPauseAndContinue = true;
            this.CanShutdown = true;

            this.eventLog.Source = Name;

            // initialize timer
            this.timer.Elapsed += this.TimerElapsed;
        }

        private void TimerElapsed(object sender, ElapsedEventArgs e)
        {
            eventLog.WriteEntry("Starting syncronization...", EventLogEntryType.Information);

            if (this.processor.PrepareToRun())
            {
                this.processor.Run();
            }
        }

I wonder what will happen if this.processor.Run() will take long time and next TimerElapsed event will be raised? Will it skip? Will it wait and run ASAP after finished? Should I consider those scenarios and code for them?

I'm using System.Timers.Timer

EDIT:

private void TimerElapsed(object sender, ElapsedEventArgs e)
        {
            eventLog.WriteEntry("Starting syncronization...", EventLogEntryType.Information);

            try
            {
                this.timer.Stop();
                if (this.processor.PrepareToRun())
                {
                    this.processor.Run();
                }
            }
            catch (Exception ex)
            {
                LoggingAndNotifications.LogAndNotify(ex);

            }
            finally
            {
                this.timer.Start();
            }
        }

EDIT 2

public Service()
        {
            this.InitializeComponent();
            this.ServiceName = Name;
            this.CanPauseAndContinue = true;
            this.CanShutdown = true;

            this.eventLog.Source = Name;

            // initialize timer
            this.timer.AutoReset = false;
            this.timer.Elapsed += this.TimerElapsed;
        }

        private void TimerElapsed(object sender, ElapsedEventArgs e)
        {
            eventLog.WriteEntry("Starting syncronization...", EventLogEntryType.Information);

            try
            {
                if (this.processor.PrepareToRun())
                {
                    this.processor.Run();
                }
            }
            catch (Exception ex)
            {
                LoggingAndNotifications.LogAndNotify(ex);
                throw;
            }
            finally
            {
                this.timer.Start();
            }
        }
like image 278
katit Avatar asked Jan 18 '12 20:01

katit


People also ask

What is TimerCallback?

Timer(TimerCallback) Initializes a new instance of the Timer class with an infinite period and an infinite due time, using the newly created Timer object as the state object.

What is timer change?

Changes the start time and the interval between method invocations for a timer, using 32-bit signed integers to measure time intervals. Change(Int64, Int64) Changes the start time and the interval between method invocations for a timer, using 64-bit signed integers to measure time intervals. Change(TimeSpan, TimeSpan)


2 Answers

It'll call it again on another thread.

Depending on the nature of the operation you will want to either:

  1. Ignore this, if the code called is safe for multiple simultaneous calls then this may be fine. Of course, you have to know that it's fine.
  2. Lock on the timer-triggered operation. Be aware that you can end up with a queue of lots of pending operations, which is very bad.
  3. Lock on the timer-triggered operation, try to obtain the lock with a timeout of zero and if you fail then skip it - there's a thread still here from the last time.
  4. Have the timer as a one-off timer that you restart at the end of each call.
like image 155
Jon Hanna Avatar answered Oct 08 '22 18:10

Jon Hanna


You can see what will happen with this sample app:

class Program
{
    static void Main(string[] args)
    {
        System.Timers.Timer timer = new System.Timers.Timer(2000);
        timer.Elapsed += new System.Timers.ElapsedEventHandler(OnTimedObject);
        timer.Start();

        while (true)
        {
        }

    }

    static void OnTimedObject(object source, ElapsedEventArgs e)
    {
        Console.WriteLine("entered");
        Thread.Sleep(3000);
        Console.WriteLine("exited");

    }
}

You'll see two 'entered' strings show up before the 'exited' first shows up. It will continue. So the threads won't step on each other.

(BTW, I'm not advocating infinite loops. :) )

like image 43
David Hoerster Avatar answered Oct 08 '22 16:10

David Hoerster