.NET - Multiple Timers instances mean Multiple Threads?

10,695

Solution 1

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.

Solution 2

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.

Solution 3

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();
        }

Solution 4

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.

Share:
10,695
André Miranda
Author by

André Miranda

As a software developer, I have around 15 years of experience in programming, being 12 of them in .NET. I worked on several types of projects for different sizes of companies (from 10 employees to 2000), projects such as MVC, background and migration processes and Windows Forms applications in three different countries. I have worked on projects for different sizes of companies (from 10 employees to 2000), using ASP.NET MVC/Core applications, background services, migration of legacy code and Windows Forms applications. About working places, I worked in three different countries: Brazil, Portugal and currently Belgium. Moreover, that multicultural opportunity made me gain knowledge, improved relationships with co-workers and improved my adaptability capabilities to different environments. I have a System Analysis and Development degree and I have achieved some Microsoft® certificates, such as Microsoft® Certified: Azure Fundamentals, Microsoft® Certified Solutions Associate: Web Applications and Microsoft® Certified Technology Specialist: .NET Framework 4, Web Applications. Through all those years, I have been working mostly with C#, ASP .NET MVC and Core (more recently), SOLID fundamentals, Design Patterns (when suitable), REST WebApi, Linq, modeling and programming with SQL Server and unit/integration tests. To support all developments, I have already worked with cache technologies like Redis and queue mechanism like RabbitMQ in Event-Driven architecture. On the Frontend domain, I worked more in the past with jQuery and more recently with Angular 6 and RxJS. On code versioning and cloud, I have experience working with Git, VSTS Azure DevOps, Azure Functions and PaaS.

Updated on June 05, 2022

Comments

  • André Miranda
    André Miranda almost 2 years

    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
    André Miranda over 10 years
    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.
  • Kevin Anderson
    Kevin Anderson over 10 years
    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.
  • user1703401
    user1703401 over 10 years
    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.
  • Brian Gideon
    Brian Gideon over 10 years
    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.
  • user1703401
    user1703401 over 10 years
    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.
  • André Miranda
    André Miranda over 10 years
    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
    André Miranda over 10 years
    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!
  • Kevin Anderson
    Kevin Anderson over 10 years
    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.
  • YK1
    YK1 over 10 years
    @Kevin: Ah, I think you are right. Thanks so much for pointing out. Made the edit.
  • YK1
    YK1 over 10 years
    @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.
  • Amrik
    Amrik about 8 years
    @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.
  • YK1
    YK1 about 8 years
    @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: msdn.microsoft.com/en-us/library/dd321473(v=vs.110).aspx