Multiple timer elapsed issue

我怕爱的太早我们不能终老 提交于 2019-12-11 10:03:16

问题


I have a timer as defined below. The timer executes a long running task. The problem i have is when the timer is running the interval has elapsed again and another timer execution starts i.e _timer_Elapsed. How can i get the timer to execute one interval after the timer has finished. The way it is now there could be multiple timer executions happening at once and that causes all sorts of issues with my code.

protected override void OnStart(string[] args)
        {

           _timer = new System.Timers.Timer();
           _timer.AutoReset = false;
           _timer.Interval = (Convert.ToInt32(ConfigurationManager.AppSettings["CheckInterval"]));
           _timer.Elapsed += new System.Timers.ElapsedEventHandler(_timer_Elapsed);
           _timer.Enabled = true;
           _timer.Start(); // Start timer 

        }


 public static void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            try
            {
                _timer.Interval = (Convert.ToInt32(ConfigurationManager.AppSettings["CheckInterval"])); 

                BLLGenericResult SystemCheckItems_Result = ServiceItemOperations.CheckItems(); // Long Running Task

            }
            catch (Exception ex)
            {
                // Exception handling...
            }
            finally
            {
                _timer.Start();
            }
        }

回答1:


Let's properly write this up. It is the Interval assignment that is getting you into trouble. A sample program that demonstrates the issue:

using System;

class Program {
    static System.Timers.Timer timer;
    static void Main(string[] args) {
        timer = new System.Timers.Timer();
        timer.AutoReset = false;
        timer.Interval = 1000;
        timer.Elapsed += timer_Elapsed;
        timer.Start();
        Console.ReadLine();
    }

    static void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {
        timer.Interval = 1000;
        Console.WriteLine("Tick");
    }
}

Output:

Tick
Tick
Tick
...

Remove the Interval assignment in the Elapsed event handler to see the difference.

So, in other words, even though the AutoReset property is false, just assigning the Interval property is enough to get the timer to restart. Big surprise of course, nobody ever sees that coming. And it plays havoc on your program because you assign the Interval property early, before you start doing the heavy lifting. So the Elapsed event will be raised again, on another thread, while your previous one hasn't completed running yet. That's a threading bug waiting to happen, particularly if your Interval value is too small. You'll need to assign it later, do so inside the finally block. Good thing that you made the Interval too small, very hard to diagnose later.

is this a c# bug ?

The C# language is off the hook, this is a .NET Framework bug. System.Timers.Timer is in general just not a very good class, it has the usability of a chainsaw without a safety switch. It was meant to make the System.Threading.Timer class more usable, in particular solving a problem with the habit of it being garbage collected too soon. One problem solved, but three new problems added. This goes back to .NET 1.0, a framework version with training wheels. They just can't fix it anymore, too much existing code will break. You really are better off with the System.Threading.Timer, just make sure to keep the object referenced in a variable. Like you already do.




回答2:


A 2017 update:

There is a new tool that can be useful with these kinds of problems.

await Task.Delay(TimeSpan.FromSeconds(x)); 


来源:https://stackoverflow.com/questions/23043736/multiple-timer-elapsed-issue

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!