C# 已停止System.Timers.Timer在设置自动重置后开始触发已用事件
我检测到C# 已停止System.Timers.Timer在设置自动重置后开始触发已用事件,c#,.net,timer,C#,.net,Timer,我检测到System.Timers.Timer的奇怪行为: 计时器以1秒的间隔创建,并且AutoReset设置为false 计时器启动,并在1秒内触发已过事件。内部事件处理程序timer.Enabled为false,这是预期的,因为AutoReset设置为false 然后,不会触发自计时器停止后预期发生的已用事件 如果现在我们将timer.AutoReset设置为true,appeased事件每1秒启动一次计时器。启用的仍然为false 这是Timercode中的一个bug,还是这种奇怪的行为可
System.Timers.Timer的奇怪行为:
计时器以1秒的间隔创建,并且AutoReset
设置为false
计时器启动,并在1秒内触发<代码>已过代码>事件。内部事件处理程序timer.Enabled
为false
,这是预期的,因为AutoReset
设置为false
然后,不会触发自计时器停止后预期发生的已用事件
如果现在我们将timer.AutoReset
设置为true
,appeased
事件每1秒启动一次<代码>计时器。启用的
仍然为false李>
这是Timer
code中的一个bug,还是这种奇怪的行为可能是有原因的
在我的理解中,停止的计时器不应该开始触发事件,即使我们更改了AutoReset
属性。
我知道在计时器停止后可以触发appeased
事件,因为执行已经在线程池中排队(问题在本文中描述)。然而,它并没有解释为什么停止计时器开始触发事件
以下是重现问题的最小示例:
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
...
根据MS 事件处理方法可能同时在一个线程上运行 另一个线程调用Stop方法或将Enabled属性设置为 错。这可能会导致在 计时器停止。Stop方法的示例代码显示了一种方法 以避免这种竞争条件 即使
SynchronizingObject
不为null,也可能发生已用事件
调用Dispose
或Stop
方法后或启用后
属性已设置为false
,因为用于引发
已用
事件始终排队等待在线程池线程上执行。
解决此竞态条件的一种方法是设置一个标志,告诉
已用事件的事件处理程序,以忽略后续事件
资料来源:
在跟踪之后,建议使用System.Timers.Timer和防止不必要的事件的第二个示例位于:
看来我之前的调查并不完全正确。我也不会说完全错误。我认为我的大部分假设都是正确的,等待反馈以改进答案
我最初的答案
a、 k.a.下降到系统的黑暗中。计时器。计时器
我没有证明这一点,我只是研究了课程的结构。这很糟糕
计时器未停止!启用!=停止
嗯,你从来没有真正调用过定时器。Stop()
是吗?正如Bob叔叔所说,编程中的许多事情都是成对的,比如调用Start
和Stop
。如果您不希望计时器对您的更改做出反应,则应停止计时器
行为是正确的
我很少使用这个类,但它的行为似乎是故意的。我知道这听起来很矛盾,但请看下面:)
查看参考源,只要调用myTimer.Start()
,每次更改属性(AutoReset
,Interval
,Enabled
),计时器就会通过名为UpdateTimer
的方法作出反应,并根据新参数集合的指示生成后续事件激发
- 这不是一个bug,但仍然有点令人不安:一个
System.Timers.Timer
的AutoReset
设置为false
,在Start()
启动一次之后,仍然会有一个System.Threading.Timer
漫游。请参见下面的解释
但是有一个状态/显示错误!至少在我看来
- 如果我们将步骤4改为更新
Interval
,这将生成一个勾号
,我希望在调用LogMessagefunction
时,计时器将启用==false
,情况已经如此
当将AutoReset
设置为true
(步骤4)时,我希望已启用
变为true
,但正如您所指出的情况并非如此。让我们挖深一点李>
可能原因状态与行为不一致
- 在Timer.cs类中,启用的
setter负责创建和处理备份字段Timer
的系统线程.Timer
实例。
- 状态从
false
更改为true
创建timer
- 状态从
true
更改为false
处理计时器
+一些其他魔法
- 使用
启用
属性的唯一方法是启动
和停止
- 当
autoreset
为false
时,用于触发事件的内部回调,MyTimerCallback
将启用的备份字段设置为false
。从某种意义上说,它是在撒谎,因为它绕过了Enabled
属性,目的是让计时器保持活动状态。如果不是这样,则该类的行为将与上述情况不同
- 我天真的头脑认为“显示错误”修复程序将在
MyTimerCallback
中,并进行与自动重置为false
时将enabled
设置为false
类似的检查。甚至可能enabled=autoreset
。这之后我需要洗个长澡,然后睡觉
资料来源:
我认为应该更新这个问题,以便更好地描述这种行为,这对我来说都是新闻:)这门课在许多方面都存在严重缺陷。那里