如何正确停止计时器

How to properly stop a timer

using System.Timers;

void CreateTimer()
{
    myTimerObject = new Timer(5000);
    myTimerObject.AutoReset = false;                 
    myTimerObject.Elapsed += MyEventOnElapsed;
    myTimerObject.Start();
}

void MyEventOnElapsed(object sender, ElapsedEventArgs e)
{
    lock(aLockObject) 
    {
         myTimerObject.Stop();
         // Perform actions that can exceed the interval time set in the timer
         myTimerObject.Start();
    }
}

void MethodTrigerredToStopTimer()
{
    lock(aLockObject)
    {
        myTimerObject.Stop();
    }
}        

在上面的代码中,我经过的事件 (MyEventOnElapsed) 需要一段时间才能完成,因此我不得不使用计时器启动和停止作为该方法的一部分。当 MethodTriggeredToStopTimer 被触发时,我们假设代码在 MyEventOnElapsed 并达到锁定,但是 MethodTriggerredToStopTimer 的线程赢得了比赛并设法获得了锁,我的计时器将被停止MethodTriggeredToStopTimer()。然而一旦锁被释放,在MyEventOnElapsed中的锁(aLockObject)处等待的执行指针将无限期地继续start/stop计时器。在这种情况下如何处理定时器?

如果您希望在管理这样的循环时通过方法调用或触发器以明确的方式停止,您将需要维护一些 boolean isStopped 或类似的:

boolean isStopped = false;

void CreateTimer()
{
    myTimerObject = new Timer(5000);
    myTimerObject.AutoReset = false;                 
    myTimerObject.Elapsed += MyEventOnElapsed;
    myTimerObject.Start();
}

void MyEventOnElapsed(object sender, ElapsedEventArgs e)
{
    lock(aLockObject) 
    {
         if (isStopped)
             return;

         myTimerObject.Stop();
         // Perform actions that can exceed the interval time set in the timer
         myTimerObject.Start();
    }
}

void MethodTrigerredToStopTimer()
{
    lock(aLockObject)
    {
        isStopped = true;
        myTimerObject.Stop();
    }
}

这一切在一个漂亮的小包装器 class 中会更加整洁,状态变量的名称类似于 Enabled 以避免与 Timer 的命名相似性混淆startstop 方法。此外,如果您最终需要跨平台支持或想要在您的过程中处理诸如取消之类的事情,我也会看一下使用 TaskTask.DelayCancellationToken 构建此循环long-运行 操作.

一个选项是在停止(禁用)它之前询问计时器是否启用了 Timer这样,如果调用 MethodTrigerredToStopTimer,它将意识到它已被故意停止,而不会再次启动它。

void MyEventOnElapsed(object sender, ElapsedEventArgs e)
{
    lock(aLockObject) 
    {
        if (myTimerObject.Enabled)
        {    try
             { 
                 myTimerObject.Stop();
                 // Perform actions that can exceed the interval time set in the timer
             }
             finally 
             {
                 myTimerObject.Start();
             }
        }
    }
}

try finally 有助于确保在您退出 lock 时重新启动计时器(即使抛出异常)。