2

I already have a windows service running with a System.Timers.Timer that do a specific work. But, I want some works to run at the same time, but in different threads.

I've been told to create a different System.Timers.Timer instance. Is this correct? Is this way works running in parallel?

for instance:

System.Timers.Timer tmr1 = new System.Timers.Timer();
tmr1.Elapsed += new ElapsedEventHandler(DoWork1);
tmr1.Interval = 5000;

System.Timers.Timer tmr2 = new System.Timers.Timer();
tmr2.Elapsed += new ElapsedEventHandler(DoWork2);
tmr2.Interval = 5000;

Will tmr1 and tmr2 run on different threads so that DoWork1 and DoWork2 can run at the same time, i.e., concurrently?

Thanks!

André Miranda
  • 6,420
  • 20
  • 70
  • 94
  • 1
    possible duplicate of [Do C# Timers elapse on a separate thread?](http://stackoverflow.com/questions/1435876/do-c-sharp-timers-elapse-on-a-separate-thread) – Brian Gideon Aug 01 '13 at 18:28
  • 1
    No, it's not the same question... – André Miranda Aug 01 '13 at 18:34
  • I've edited the question... I mean multiple Timer instances... – André Miranda Aug 01 '13 at 18:35
  • I retracted my close vote. – Brian Gideon Aug 01 '13 at 18:50
  • `same time, but in different threads` why? Is it a problem if you use one timer and do both the things one after another in same timer's elapsed event? Even if 2 timers guarantee two threads, there is no guarantee they will run `at same time` - it will depend on thread scheduling. – YK1 Aug 01 '13 at 18:52
  • Some works may take too long, so some works should run in parallel with the shorter works. It's a prerequisite. – André Miranda Aug 01 '13 at 19:02
  • But the prerequisite does not make sense. If one is shorter than other , how will you make 2 times tick at same time subsequently? – YK1 Aug 01 '13 at 19:15
  • Please, stick to what I've said in the question. Specially to "Will tmr1 and tmr2 run on different threads so that DoWork1 and DoWork2 can run at the same time, i.e., concurrently?" – André Miranda Aug 01 '13 at 19:16
  • Maybe when they tick first time together, they will run on different threads and _possibly_ concurrently. But you also have to think about subsequent ticks if one work is shorter than other. – YK1 Aug 01 '13 at 19:19

4 Answers4

6

It is not incorrect.

Be careful. System.Timers.Timer will start a new thread for every Elapsed event. You'll get in trouble when your Elapsed event handler takes too long. Your handler will be called again on another thread, even though the previous call wasn't completed yet. This tends to produce hard to diagnose bugs. Something you can avoid by setting the AutoReset property to false. Also be sure to use try/catch in your event handler, exceptions are swallowed without diagnostic.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • But, let's suppose I will handle elapsed to not call another event until the previous isn't completed. So, if I create a Timer timer1 and a Timer timer2, will each one run on a different thread? That's my doubt. – André Miranda Aug 01 '13 at 18:41
  • See below Hans. Maybe it *can* start a new thread for each Elapsed event, but it doesn't need to, and didn't in the small sample program below. – Kevin Anderson Aug 01 '13 at 18:47
  • You don't get to "handle elapsed", the Timer does. Sure, if you have two timers then you automatically can have two Elapsed event handlers. They operate completely independently from each other and their execution can and will overlap. – Hans Passant Aug 01 '13 at 18:51
  • 1
    It is a bit unclear why we need to keep saying "yes". At this point you should write a little console mode app and actually *try* it. – Hans Passant Aug 01 '13 at 19:01
  • And that's still very unclear to me, so I've edited my answer twice to clarify it. I don't see the problem in doing that and I also I have no problem in do my own research. So I'm asking you guys for helping me clariry the concept, ok? I always think that what is site all about. – André Miranda Aug 01 '13 at 19:07
5

Multiple timers might mean multiple threads. If two timer ticks occur at the same time (i.e. one is running and another fires), those two timer callbacks will execute on separate threads, neither of which will be the main thread.

It's important to note, though, that the timers themselves don't "run" on a thread at all. The only time a thread is involved is when the timer's tick or elapsed event fires.

On another note, I strongly discourage you from using System.Timers.Timer. The timer's elapsed event squashes exceptions, meaning that if an exception escapes your event handler, you'll never know it. It's a bug hider. You should use System.Threading.Timer instead. System.Timers.Timer is just a wrapper around System.Threading.Timer, so you get the same timer functionality without the bug hiding.

See Swallowing exceptions is hiding bugs for more info.

Jim Mischel
  • 131,090
  • 20
  • 188
  • 351
4

Will tmr1 and tmr2 run on different threads so that DoWork1 and DoWork2 can run at the same time, i.e., concurrently?

At the start, yes. However, what is the guarantee both DoWork1 and DoWork2 would finish within 5 seconds? Perhaps you know the code inside DoWorkX and assume that they will finish within 5 second interval, but it may happen that system is under load one of the items takes more than 5 seconds. This will break your assumption that both DoWorkX would start at the same time in the subsequent ticks. In that case even though your subsequent start times would be in sync, there is a danger of overlapping current work execution with work execution which is still running from the last tick.

If you disable/enable respective timers inside DoWorkX, however, your start times will go out of sync from each other - ultimately possible they could get scheduled over the same thread one after other. So, if you are OK with - subsequent start times may not be in sync - then my answer ends here.

If not, this is something you can attempt:

static void Main(string[] args)
        {
            var t = new System.Timers.Timer();
            t.Interval = TimeSpan.FromSeconds(5).TotalMilliseconds;

            t.Elapsed += (sender, evtArgs) =>
            {
                var timer = (System.Timers.Timer)sender;
                timer.Enabled = false; //disable till work done

                // attempt concurrent execution
                Task work1 = Task.Factory.StartNew(() => DoWork1());
                Task work2 = Task.Factory.StartNew(() => DoWork2());


                Task.Factory.ContinueWhenAll(new[]{work1, work2}, 
                            _ => timer.Enabled = true); // re-enable the timer for next iteration
            };

            t.Enabled = true;

            Console.ReadLine();
        }
YK1
  • 7,327
  • 1
  • 21
  • 28
  • Thanks for your answer! That was so close to finally clarify my doubt! :-) But, let's forget about "start same time", I used the wrong words. My key point is "concurrently", that is I'm looking for. Going back to the code on my question... independently DoWork1() and DoWork2() take different time to be done and suppose I Enable/Disable timers, creating 2 timers will guarantee the DoWork1() and DoWork2() run concurrently always? Thanks again! – André Miranda Aug 02 '13 at 12:43
  • I like your code, but your first paragraph is wrong, because the timer keeps going, regardless of how long execution takes. From my post where I quote MSDN: If processing of the Elapsed event lasts longer than Interval, the event might be raised again on another ThreadPool thread. In this situation, the event handler should be reentrant. – Kevin Anderson Aug 02 '13 at 14:38
  • @Kevin: Ah, I think you are right. Thanks so much for pointing out. Made the edit. – YK1 Aug 02 '13 at 15:20
  • @AndreMiranda: By _concurrent_ my understanding is that both methods run at same time (at least approximately). If you enable/disable individual timer within their handlers, subsequent ticks would go out of sync and wont run at _same_ time. Nevertheless, the important thing is that a timer is _not associated_ with a thread. Each tick of a timer is scheduled on any random thread in threadpool. So, if their start times are not in sync, they can possibly get scheduled on same thread. – YK1 Aug 02 '13 at 20:15
  • @YK1 how i can use try catch and finally with this? i was curious if i can catch any error and reset timer in finally blog. – Amrik Feb 04 '16 at 00:52
  • @Amrik: There are n number of ways to answer your question. If you want `try/finally` syntax then you can change the timer delegate to `async` and use `async/await` syntax. But in my answer I had used classical `Task` syntax as question marked for `.NET 4.0`. Here irrespective of whether the tasks throw exception, the timer will be enabled. However if you want to perform some special operation when exception, then you can check TaskStatus.Faulted. See example here: https://msdn.microsoft.com/en-us/library/dd321473(v=vs.110).aspx – YK1 Feb 04 '16 at 15:04
2

Kind of. First, check out the MSDN page for System.Timers.Timer: http://msdn.microsoft.com/en-us/library/system.timers.timer.aspx

The section you need to be concerned with is quoted below:

If the SynchronizingObject property is null, the Elapsed event is raised on a ThreadPool thread. If processing of the Elapsed event lasts longer than Interval, the event might be raised again on another ThreadPool thread. In this situation, the event handler should be reentrant.

Basically, this means that where the Timer's action gets run is not such that each Timer has its own thread, but rather that by default, it uses the system ThreadPool to run the actions.

If you want things to run at the same time (kick off all at the same time) but run concurrently, you can not just put multiple events on the elapsed event. For example, I tried this in VS2012:

    static void testMethod(string[] args)
    {
        System.Timers.Timer mytimer = new System.Timers.Timer();
        mytimer.AutoReset = false;
        mytimer.Interval = 3000;

        mytimer.Elapsed += (x, y) => {
            Console.WriteLine("First lambda.  Sleeping 3 seconds");
            System.Threading.Thread.Sleep(3000);
            Console.WriteLine("After sleep");
        };
        mytimer.Elapsed += (x, y) => { Console.WriteLine("second lambda"); };
        mytimer.Start();
        Console.WriteLine("Press any key to go to end of method");
        Console.ReadKey();
    }

The output was this:

Press any key to go to end of method

First lambda.

Sleeping 3 seconds

After sleep

second lambda

So it executes them consecutively not concurrently. So if you want "a bunch of things to happen" upon each timer execution, you have to launch a bunch of tasks (or queue up the ThreadPool with Actions) in your Elapsed handler. It may multi-thread them, or it may not, but in my simple example, it did not.

Try my code yourself, it's quite simple to illustrate what's happening.

Kevin Anderson
  • 6,850
  • 4
  • 32
  • 54
  • This is really good information and there is nothing wrong with this answer. However, because the OP mentioned a windows service it is *probably* safe to assume that `SynchronizingObject` will be `null`. – Brian Gideon Aug 01 '13 at 18:54