停止时同步 Timers.Timer elapsed 方法
参考MSDN关于系统.定时器.定时器:
Timer.Elapsed 事件是在 ThreadPool线程,所以 事件处理方法可能运行在一个 线程同时调用 Timer.Stop 方法在另一个上运行 线。这可能会导致 经过的事件在之后引发 调用停止方法。本次比赛 无法简单地预防这种情况 通过比较 SignalTime 属性 与停止方法时的时间 调用,因为事件处理 方法可能已经在执行 Stop 方法被调用,或者可能 在那一刻之间开始执行 当调用 Stop 方法并且 停止时间被保存的时刻。如果 防止线程很关键 调用 Stop 方法 事件处理过程中继续进行 方法仍在执行,请使用 more 强大的同步机制,例如 作为 Monitor 类或 比较交换方法。使用的代码 CompareExchange 方法可以是 在示例中发现 Timer.Stop方法。
谁能举一个“强大的同步机制,例如Monitor类”的例子来解释这到底意味着什么?
我认为这意味着以某种方式使用锁,但我不确定你将如何实现它。
With reference to this quote from MSDN about the System.Timers.Timer:
The Timer.Elapsed event is raised on a
ThreadPool thread, so the
event-handling method might run on one
thread at the same time that a call to
the Timer.Stop method runs on another
thread. This might result in the
Elapsed event being raised after the
Stop method is called. This race
condition cannot be prevented simply
by comparing the SignalTime property
with the time when the Stop method is
called, because the event-handling
method might already be executing when
the Stop method is called, or might
begin executing between the moment
when the Stop method is called and the
moment when the stop time is saved. If
it is critical to prevent the thread
that calls the Stop method from
proceeding while the event-handling
method is still executing, use a more
robust synchronization mechanism such
as the Monitor class or the
CompareExchange method. Code that uses
the CompareExchange method can be
found in the example for the
Timer.Stop method.
Can anyone give an example of a "robust synchronization mechanism such as the Monitor class" to explain what this means exactly?
I am thinking it means use a lock somehow, but I am unsure how you would implement that.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
可靠地停止 System.Timers.Timer 确实是一项重大工作。最严重的问题是,由于线程池调度程序算法,用于调用 Elapsed 事件的线程池线程可能会备份。拥有几个备份呼叫并不罕见,拥有数百个在技术上是可能的。
您将需要两个同步,一个用于确保仅在没有运行 Elapsed 事件处理程序时停止计时器,另一个用于确保这些备份的 TP 线程不会造成任何损害。像这样:
考虑将 AutoReset 属性设置为 false。这是脆弱的另一种方式,Elapsed 事件是从捕获异常的内部 .NET 方法调用的。非常令人讨厌,您的计时器代码在没有任何诊断的情况下停止运行。我不知道历史,但 MSFT 一定有另一个团队对这种混乱感到气喘吁吁,并编写了 System.Threading.Timer。强烈推荐。
Stopping a System.Timers.Timer reliably is indeed a major effort. The most serious problem is that the threadpool threads that it uses to call the Elapsed event can back up due to the threadpool scheduler algorithm. Having a couple of backed-up calls isn't unusual, having hundreds is technically possible.
You'll need two synchronizations, one to ensure you stop the timer only when no Elapsed event handler is running, another to ensure that these backed-up TP threads don't do any harm. Like this:
Consider setting the AutoReset property to false. That's brittle another way, the Elapsed event gets called from an internal .NET method that catches Exception. Very nasty, your timer code stops running without any diagnostic at all. I don't know the history, but there must have been another team at MSFT that huffed and puffed at this mess and wrote System.Threading.Timer. Highly recommended.
这就是它所暗示的。
Monitor
是类C# 编译器将其用于lock
语句。话虽如此,只有当您的情况存在问题时,上述问题才是问题。整个语句基本上可以翻译为“您可以在调用 Stop() 后立即获得一个发生的计时器事件。如果这是一个问题,您需要处理它。”根据您的计时器正在执行的操作,这可能是一个问题,也可能不是。
如果出现问题,Timer.Stop页面显示了一种强大的方法(使用 Interlocked.CompareExchange)来处理此问题。只需复制示例中的代码并根据需要进行修改即可。
That is what it is suggesting.
Monitor
is the class that's used by the C# compiler for alock
statement.That being said, the above is only a problem if it is an issue in your situation. The entire statement basically translates to "You could get a timer event that happens right after you call Stop(). If this is a problem, you'll need to deal with it." Depending on what your timer is doing, it may be an issue, or it may not.
If it's a problem, the Timer.Stop page shows a robust way (using Interlocked.CompareExchange) to handle this. Just copy the code from the sample and modify as necessary.
尝试:
Try:
这是防止这种竞争条件发生的非常简单的方法:
Here is a very simple way to prevent this race condition from occurring:
看来计时器不是线程安全的。您必须通过锁定保持对它的所有调用同步。 lock(object){} 实际上只是简单监视器调用的简写。
Seems timer is not thread safe. You must keep all calls to it in sync via locking. lock(object){} is actually just short hand for a simple monitor call.