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
      。这之后我需要洗个长澡,然后睡觉
    资料来源:


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

    这门课在许多方面都存在严重缺陷。那里