多个计时器已过期问题

时间:2014-04-13 14:08:02

标签: c# timer system.timers.timer

我有一个如下定义的计时器。计时器执行长时间运行的任务。我遇到的问题是,当计时器运行时,间隔已经过了,另一个计时器执行开始,即_timer_Elapsed。如何在定时器完成后让定时器执行一个时间间隔。它现在的方式可能会同时发生多个计时器执行,这会导致我的代码出现各种问题。

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

2 个答案:

答案 0 :(得分:3)

让我们正确地写下来。正是Interval任务让你陷入困境。一个演示该问题的示例程序:

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

输出:

Tick
Tick
Tick
...

删除Elapsed事件处理程序中的Interval分配以查看差异。

因此,换句话说,即使AutoReset属性为 false ,只需分配Interval属性就足以让计时器重新启动。当然,大惊喜,没有人看到过这种情况。它会对你的程序造成严重破坏,因为你提前分配Interval属性,之前你开始做繁重的工作。因此,Elapsed事件将在另一个线程上再次引发,而您之前的事件尚未完成运行。这是一个等待发生的线程错误,特别是如果您的Interval值太小。您需要稍后分配,在 finally 块中执行此操作。你把Interval做得太小,以后很难诊断的好事。

  

这是一个c#bug吗?

C#语言已经摆脱困境,这是一个.NET Framework错误。 System.Timers.Timer通常不是一个非常好的类,它具有没有安全开关的电锯的可用性。它的目的是使System.Threading.Timer类更加可用,特别是解决了过早收集垃圾的习惯问题。一个问题解决了,但增加了三个新问题。这可以追溯到.NET 1.0,这是一个带有训练轮的框架版本。他们再也无法解决它,现有的代码太多会破坏。你最好使用System.Threading.Timer,只需确保在变量中保留引用的对象。就像你已经做的那样。

答案 1 :(得分:0)

2017年更新:

有一种新工具可以解决这些问题。

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