停止时同步Timers.Timer经过的方法

时间:2011-01-26 21:56:51

标签: c# .net synchronization timer

参考MSDN关于System.Timers.Timer:

的引用
  

在a上引发Timer.Elapsed事件   ThreadPool线程,所以   事件处理方法可能在一个上运行   线程同时调用一个   Timer.Stop方法在另一个上运行   线。这可能会导致   经过的事件被提升了   调用Stop方法。这场比赛   条件不能简单地防止   通过比较SignalTime属性   与Stop方法的时间相同   叫,因为事件处理   方法可能已经在执行时   调用Stop方法,或者可能   从那一刻开始执行   什么时候调用Stop方法和   保存停止时间的时刻。如果   防止线程至关重要   从中调用Stop方法   在事件处理过程中进行   方法仍在执行,使用更多   强大的同步机制等   作为Monitor类或者   CompareExchange方法。使用的代码   CompareExchange方法可以   在示例中找到了   Timer.Stop方法。

任何人都可以提供一个“强大的同步机制,例如Monitor类”来解释这究竟意味着什么吗?

我认为这意味着以某种方式使用锁定,但我不确定如何实现它。

5 个答案:

答案 0 :(得分:12)

可靠地停止System.Timers.Timer确实是一项重大工作。最严重的问题是它用于调用Elapsed事件的线程池线程可以由于线程池调度程序算法而备份。进行几次备份呼叫并不罕见,技术上有数百种可能。

您需要两个同步,一个用于确保仅在没有运行Elapsed事件处理程序时停止计时器,另一个用于确保这些备份的TP线程不会造成任何伤害。像这样:

    System.Timers.Timer timer = new System.Timers.Timer();
    object locker = new object();
    ManualResetEvent timerDead = new ManualResetEvent(false);

    private void Timer_Elapsed(object sender, ElapsedEventArgs e) {
        lock (locker) {
            if (timerDead.WaitOne(0)) return;
            // etc...
        }
    }

    private void StopTimer() {
        lock (locker) {
            timerDead.Set();
            timer.Stop();
        }
    }

考虑将AutoReset属性设置为false。这是另一种方式,Elapsed事件从一个捕获异常的内部.NET方法调用。非常讨厌,你的计时器代码停止运行,没有任何诊断。我不知道历史,但是MSFT的其他团队肯定已经在这个烂摊子里喘不过气来,写了System.Threading.Timer。强烈推荐。

答案 1 :(得分:0)

这就是它的建议。

Monitor是C#编译器用于lock语句的类。

话虽如此,如果在您的情况下出现问题,上述问题只是一个问题。整个语句基本上都转换为“你可以在调用Stop()之后立即获得一个计时器事件。如果这是一个问题,你需要处理它。”根据您的计时器正在做什么,这可能是一个问题,或者可能不是。

如果这是一个问题,Timer.Stop页面会显示一种强大的方式(使用Interlocked.CompareExchange)来处理此问题。只需复制样本中的代码并根据需要进行修改。

答案 2 :(得分:0)

尝试:

lock(timer) {
timer.Stop();
}

答案 3 :(得分:0)

这是防止这种竞争条件发生的一种非常简单的方法:

private object _lock = new object();
private Timer _timer; // init somewhere else

public void StopTheTimer()
{
    lock (_lock) 
    {
        _timer.Stop();
    }
}

void elapsed(...)
{
    lock (_lock)
    {
        if (_timer.Enabled) // prevent event after Stop() is called
        {
            // do whatever you do in the timer event
        }
    }
}

答案 4 :(得分:0)

似乎计时器不是线程安全的。您必须通过锁定保持对它的所有呼叫同步。 lock(object){}实际上只是一个简单的监视器调用的简写。