多个计时器已过问题
Posted
技术标签:
【中文标题】多个计时器已过问题【英文标题】:Multiple timer elapsed issue 【发布时间】:2014-05-27 10:44:21 【问题描述】:我有一个如下定义的计时器。计时器执行一个长时间运行的任务。我遇到的问题是当计时器运行时,间隔再次过去,另一个计时器执行开始,即_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();
【问题讨论】:
这是不可能的,使用 AutoReset = false 确保计时器不会再次触发,除非您明确重新启用它。您很可能会以错误的方式进行操作,例如在 Elapsed 事件处理程序的开头而不是结尾重新启用它。或者没有正确实现 OnStop() 方法。 @HansPassant 是的 - 我也在读这个 - 让我提出我的 _Timer_Elapsed 方法,看看你的想法 或者...您再次调用了 OnStart 函数,并且除了前一个仍在运行的计时器之外,还启动了一个新计时器。 @SteveWellens 我不这么认为 - OnStart 只调用一次 - 在 Windows 服务启动时 将间隔分配也移到底部。又一个 System.Timers.Timer 怪癖。 【参考方案1】:让我们正确地写下来。给你带来麻烦的是间隔分配。演示该问题的示例程序:
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 Framework 错误。 System.Timers.Timer 通常不是一个很好的类,它具有没有安全开关的电锯的可用性。它旨在使 System.Threading.Timer 类更有用,特别是解决过早收集垃圾的习惯问题。解决了一个问题,但又增加了三个新问题。这可以追溯到 .NET 1.0,这是一个带有训练轮的框架版本。他们只是无法再修复它,太多现有代码会破坏。使用 System.Threading.Timer 确实更好,只需确保将引用的对象保留在变量中。就像你已经做的那样。
【讨论】:
这里的细节令人印象深刻——非常感谢。【参考方案2】:2017 年更新:
有一种新工具可以用来解决这类问题。
await Task.Delay(TimeSpan.FromSeconds(x));
【讨论】:
以上是关于多个计时器已过问题的主要内容,如果未能解决你的问题,请参考以下文章