gpt4 book ai didi

c# - Stopped System.Timers.Timer 在设置 AutoReset 后开始触发 Elapsed 事件

转载 作者:行者123 更新时间:2023-11-30 18:15:03 25 4
gpt4 key购买 nike

我检测到 System.Timers.Timer 的奇怪行为:

  1. 计时器以 1 秒的间隔创建,AutoReset 设置为 false
  2. 计时器启动,Elapsed 事件在 1 秒后触发。内部事件处理程序 timer.Enabledfalse,这是预期的,因为 AutoReset 已设置为 false
  3. 然后不会触发 Elapsed 事件,这是预期的,因为计时器已停止。
  4. 如果现在我们将 timer.AutoReset 设置为 trueElapsed 事件开始每 1 秒触发一次。 timer.Enabled 仍然是 false。

它是 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
...

最佳答案

根据 MS

The event-handling method might run on one thread at the same time that another thread calls the Stop method or sets the Enabled property to false. This might result in the Elapsed event being raised after the timer is stopped. The example code for the Stop method shows one way to avoid this race condition.

Even if SynchronizingObject is not null, Elapsed events can occur after the Dispose or Stop method has been called or after the Enabled property has been set to false, because the signal to raise the Elapsed event is always queued for execution on a thread pool thread. One way to resolve this race condition is to set a flag that tells the event handler for the Elapsed event to 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

看来我之前的调查并不完全正确。我也不会说完全错了。我认为我的大部分假设都是正确的,等待反馈以改进答案!

我的原始答案

又名下降到 System.Timers.Timer 的黑暗中

我还没有证明这些,我只研究了类的结构。不好...

计时器没有停止!已启用!=已停止

那么,您现在从未真正调用过 timer.Stop(),对吗?正如 Bob 大叔所说,编程中的许多事情都是成对出现的,例如调用 StartStop。如果您不希望它对您的更改使用react,您应该停止计时器!

行为是正确的

我很少使用这个类,但这种行为似乎是设计使然。我知道这听起来很矛盾,但请阅读下文 :)

查看引用源,一调用myTimer.Start(),每次更改属性(AutoReset,Interval,Enabled),计时器通过称为 UpdateTimer 的方法作出 react ,根据新参数集合的指示生成后续事件触发。

  • 不是错误,但仍然有点令人不安:在 之后 AutoReset 设置为 falseSystem.Timers.Timer Start() 并触发一次,仍然会有 System.Threading.Timer 漫游。请参阅下面的解释。

但是有一个状态/显示错误!至少在我看来

  • 如果我们将第 4 步更改为更新 Interval,这将生成一个 tick,我希望计时器具有 Enabled==falseLogMessagefunction 被调用时,已经是这种情况了。
  • AutoReset 设置为 true 时,(第 4 步)我希望 Enabled 变为 true,这正如您指出的那样,情况并非如此。让我们深入挖掘!

状态与行为不一致的可能原因

  • 在 Timer.cs 类中,Enabled setter 负责为支持字段 timer 创建和处理 System.Threading.Timer 实例>。
    • falsetrue 的状态变化创建了 timer
    • 状态从 truefalse 处理 timer + 一些其他魔法。
  • 使用 Enabled 属性的唯一方法是 StartStop
  • 用于触发事件的内部回调 MyTimerCallback,在 autoreset 时将 enabled 支持字段设置为 false > 为 false。从某种意义上说,它是在说谎,因为它故意绕过 Enabled 属性以保持 timer 事件和启动。否则,类的行为就不会像上面描述的那样。
  • 我的天真想法认为“显示错误”修复将在 MyTimerCallback 中进行,与将 enabled 设置为 false 的检查类似> 当 autoreset 为 false 时。甚至可能 enabled = autoreset。之后我需要洗个长澡,然后去 sleep =))

来源:https://referencesource.microsoft.com/#System/services/timers/system/timers/Timer.cs,050a7911a328d317

我认为应该更新问题以更好地描述行为,这对我来说都是新闻:)

关于c# - Stopped System.Timers.Timer 在设置 AutoReset 后开始触发 Elapsed 事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49115618/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com