Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent System.Timers.Timer from queuing for execution on a thread pool?

There is a problem with standard System.Timers.Timer behaviour. The timer raise Elapsed event with some interval. But when time of execution inside Elapsed event handler exceed timer interval then thread pool begin queuing event handling. This is a problem in my case. This is because with my Elapsed event handler I fetch some data from database and doing something with it and finally save results back to database. But data handling should be provided only once. So, is there a way to prevent from queuing elapse events for System.Timers.Timer.

As illustration for this issue you can consider next test program:

public class EntryPoint
{

    private static void TimeProc(object state, ElapsedEventArgs e)
    {
        Console.WriteLine("Current time {0} on the thread {1}", DateTime.Now, Thread.CurrentThread.ManagedThreadId);
        Thread.Sleep(20000);
    }

    static void Main(string[] args)
    {
        Console.WriteLine("Press <Enter> for finishing\n\n");
        ThreadPool.SetMaxThreads(10, 10);
        System.Timers.Timer MyTimer = new System.Timers.Timer(1000);
        MyTimer.Elapsed += new ElapsedEventHandler(TimeProc);
        MyTimer.Start();
        Console.ReadLine();
        MyTimer.Stop();
    }
}

And possible output will be as here:

Current time 03.02.2011 0:00:09 on the thread 4
Current time 03.02.2011 0:00:10 on the thread 5
Current time 03.02.2011 0:00:12 on the thread 6
Current time 03.02.2011 0:00:13 on the thread 7
Current time 03.02.2011 0:00:14 on the thread 8
Current time 03.02.2011 0:00:15 on the thread 9
Current time 03.02.2011 0:00:16 on the thread 10
Current time 03.02.2011 0:00:17 on the thread 11
Current time 03.02.2011 0:00:18 on the thread 12
Current time 03.02.2011 0:00:19 on the thread 13
Current time 03.02.2011 0:00:30 on the thread 4
Current time 03.02.2011 0:00:30 on the thread 5

Possible solutions:

1) It was inspired by:C# Timer vs Thread in Service

And has a code like here regarding to mentioned above sample:

    public class EntryPoint
    {
        private static System.Timers.Timer MyTimer;
        private static void TimeProc(object state, ElapsedEventArgs e)
        {
            Console.WriteLine("Current time {0} on the thread {1}", DateTime.Now, Thread.CurrentThread.ManagedThreadId);
            Thread.Sleep(20000);
            MyTimer.Enabled = true;
        }

        static void Main(string[] args)
        {
            Console.WriteLine("Press <Enter> for finishing\n\n");
            ThreadPool.SetMaxThreads(10, 10);
            MyTimer = new System.Timers.Timer(1000);
            MyTimer.AutoReset = false;

            MyTimer.Elapsed += new ElapsedEventHandler(TimeProc);
            MyTimer.Enabled = true;
            Console.ReadLine();

        }
    }

2) Second way is about SynchronizingObject, but it is a valuable only for Windows form application or required additional development of code for implementing object that would be implements ISynchronizeInvoke interface. More about this way you can find here

So, for now I will prefer first solution.

like image 419
apros Avatar asked Feb 02 '11 15:02

apros


2 Answers

What I usually do in this case is stop the timer at the start of the Elapsed handler and start it again at the end. This way, you are only handling one tick at a time.

UPDATE:

Per the MSDN link, I think what they mean is that you can set your own flag (but still have the ticks come in), but thread safety measures should be taken as well.

like image 170
Mark Avenius Avatar answered Sep 21 '22 13:09

Mark Avenius


I would say simply stop it and then start it after your lengthy execution like this.

tmr.Stop();
//Your lengthy execution code goes here
tmr.Start();
like image 42
Shekhar_Pro Avatar answered Sep 18 '22 13:09

Shekhar_Pro