多个计时器超时问题

本文关键字:问题 超时 计时器 | 更新日期: 2023-09-27 17:58:10

我有一个如下定义的计时器。计时器执行长时间运行的任务。我遇到的问题是,当计时器运行时,间隔再次过去,另一个计时器开始执行,即_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();
            }
        }

多个计时器超时问题

让我们正确地写出来。正是间隔分配给你带来了麻烦。演示该问题的示例程序:

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块中进行分配。好在你让间隔太小了,以后很难诊断。

这是一个c错误吗?

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

2017年更新:

有一种新的工具可以用来解决这类问题。

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