参考MSDN关于System.Timers.Timer:
的引用在a上引发Timer.Elapsed事件 ThreadPool线程,所以 事件处理方法可能在一个上运行 线程同时调用一个 Timer.Stop方法在另一个上运行 线。这可能会导致 经过的事件被提升了 调用Stop方法。这场比赛 条件不能简单地防止 通过比较SignalTime属性 与Stop方法的时间相同 叫,因为事件处理 方法可能已经在执行时 调用Stop方法,或者可能 从那一刻开始执行 什么时候调用Stop方法和 保存停止时间的时刻。如果 防止线程至关重要 从中调用Stop方法 在事件处理过程中进行 方法仍在执行,使用更多 强大的同步机制等 作为Monitor类或者 CompareExchange方法。使用的代码 CompareExchange方法可以 在示例中找到了 Timer.Stop方法。
任何人都可以提供一个“强大的同步机制,例如Monitor类”来解释这究竟意味着什么吗?
我认为这意味着以某种方式使用锁定,但我不确定如何实现它。
答案 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){}实际上只是一个简单的监视器调用的简写。