我检测到System.Timers.Timer
的奇怪行为:
AutoReset
设置为false
。Elapsed
事件。由于timer.Enabled
设置为false
,因此内部事件处理程序AutoReset
为false
。Elapsed
个事件。timer.AutoReset
设置为true
,Elapsed
事件每1秒开始触发一次。 timer.Enabled
仍然是假的。 这是Timer
代码中的错误还是可能有这种奇怪行为的原因?
根据我的理解,即使我们更改了AutoReset
属性,停止的计时器也不应该开始触发事件。
我知道在计时器停止后可能会触发Elapsed
事件,因为执行已在线程池中排队(问题在此question中描述)。但是它没有解释为什么停止计时器开始触发事件。
以下是重现问题的最小样本:
class Program
{
private static System.Timers.Timer timer;
static void Main(string[] args)
{
timer = new System.Timers.Timer
{
AutoReset = false,
Interval = 1000
};
timer.Elapsed += TimerTick;
LogMessage("Starting timer...");
timer.Start();
Thread.Sleep(3000);
LogMessage($"Timer is {(timer.Enabled ? "enabled" : "stopped")}");
LogMessage("Setting AutoReset to true");
timer.AutoReset = true;
Thread.Sleep(Int32.MaxValue);
}
private static void TimerTick(object sender, ElapsedEventArgs e)
{
LogMessage($"Timer Tick: timer.Enabled is {timer.Enabled}");
}
private static void LogMessage(string message)
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} {message}");
}
}
节目输出:
19:46:23.043 Starting timer...
19:46:24.068 Timer Tick: timer.Enabled is False
19:46:26.053 Timer is stopped
19:46:26.057 Setting AutoReset to true
19:46:27.100 Timer Tick: timer.Enabled is False
19:46:28.103 Timer Tick: timer.Enabled is False
19:46:29.117 Timer Tick: timer.Enabled is False
19:46:30.130 Timer Tick: timer.Enabled is False
19:46:31.144 Timer Tick: timer.Enabled is False
19:46:32.158 Timer Tick: timer.Enabled is False
...
答案 0 :(得分:0)
根据MS
事件处理方法可能同时在一个线程上运行 另一个线程调用Stop方法或将Enabled属性设置为 假。这可能导致在之后引发Elapsed事件 计时器停止。 Stop方法的示例代码显示了一种方法 避免这种竞争条件。
即使
SynchronizingObject
不为null,也可能发生Elapsed事件 调用Dispose
或Stop
方法后或Enabled
之后 属性已设置为false
,因为信号提升了Elapsed
事件总是排队等待在线程池线程上执行。 解决这种竞争条件的一种方法是set a flag
告诉你Elapsed
事件的事件处理程序到ignore subsequent events
。
来源:https://msdn.microsoft.com/en-us/library/system.timers.timer.elapsed(v=vs.110).aspx
在跟踪之后,使用System.Timers.Timer和防止不需要的events
的推荐样本是第二个样本:
https://msdn.microsoft.com/en-us/library/system.timers.timer.stop(v=vs.110).aspx
看来我之前的调查并不完全正确。我也不会说完全错。我认为我的大部分假设都是正确的,等待反馈以改善答案!
我还没有证明这一点,我只研究了班级的结构。这很糟糕......
计时器未停止!已启用!=已停止
好吧,你现在从未真正致电timer.Stop()
,是吗?就像鲍勃叔叔所说的那样,编程中的许多东西成对出现,例如调用Start
和Stop
。如果您不希望它对您的更改作出反应,您应该Stop
计时器!
行为正确
我很少使用这个类,但行为似乎是设计的。我知道这听起来是矛盾的,但请阅读以下内容:)
查看参考来源,只要您拨打myTimer.Start()
,每次更改属性(AutoReset
,Interval
,Enabled
)时,定时器都会做出反应一个名为UpdateTimer
的方法,在新参数集合指示时生成后续事件触发。
System.Timers.Timer
AutoReset
false
设置为Start()
,System.Threading.Timer
之后发射一次,仍会有{{1} }} 四处闲逛。请参阅下面的说明。但是有状态/显示错误!至少在我看来
Interval
而生成tick
,我会希望在调用Enabled==false
时计时器为LogMessagefunction
,已经是这样了。AutoReset
设置为true
时,(步骤4)我希望Enabled
成为true
,正如您所指出的那样。Enabled
并非如此。让我们深入挖掘!状态与行为不一致的可能原因
System.Threading.Timer
setter负责为支持字段timer
创建和部署false
个实例。
true
更改为timer
会创建true
false
更改为timer
处置Enabled
+其他一些魔法。Start
属性的唯一方法是Stop
和MyTimerCallback
enabled
为false
时,用于触发事件的内部回调autoreset
会将false
支持字段设置为Enabled
。从某种意义上说,它是谎言,因为它有意绕过timer
属性以保持MyTimerCallback
活着和踢。如果不是,则该类的行为将不会如上所述。enabled
中,当自动设置为false
时,对{1}}到false
的设置进行类似检查。甚至可能enabled = autoreset
。我需要在此之后长时间洗澡,然后去睡觉=))我认为应该更新问题以更好地描述行为,这对我来说都是新闻:)