问题描述
我有一个用C#实现的Windows服务,它需要经常做一些工作.我已经使用 System.Threading.Timer
和一个负责安排下一个回调的回调方法来实现此功能.我在优雅地停止(即处置)计时器时遇到麻烦.以下是一些可以在控制台应用程序中运行的简化代码,这些代码说明了我的问题:
I have a Windows Service implemented in C# that needs to do some work every so often. I've implemented this using a System.Threading.Timer
with a callback method that is responsible for scheduling the next callback. I am having trouble gracefully stopping (i.e. disposing) the timer. Here's some simplified code you can run in a console app that illustrates my problem:
const int tickInterval = 1000; // one second
timer = new Timer( state => {
// simulate some work that takes ten seconds
Thread.Sleep( tickInterval * 10 );
// when the work is done, schedule the next callback in one second
timer.Change( tickInterval, Timeout.Infinite );
},
null,
tickInterval, // first callback in one second
Timeout.Infinite );
// simulate the Windows Service happily running for a while before the user tells it to stop
Thread.Sleep( tickInterval * 3 );
// try to gracefully dispose the timer while a callback is in progress
var waitHandle = new ManualResetEvent( false );
timer.Dispose( waitHandle );
waitHandle.WaitOne();
问题是当 waitHandle.WaitOne
被阻止时,我从回调线程上的 timer.Change
获得了 ObjectDisposedException
.我在做什么错了?
The problem is that I get an ObjectDisposedException
from timer.Change
on the callback thread while waitHandle.WaitOne
is blocking. What am I doing wrong?
用于 Dispose
的文档我正在使用的超载说:
The documentation for the Dispose
overload I'm using says:
看来文档中的这一说法可能不正确.有人可以验证吗?
我知道我可以通过在回调和处理代码之间添加一些信号来解决该问题,如下面的Henk Holterman所建议的那样,但是除非绝对必要,否则我不想这样做.
I know that I could work around the problem by adding some signaling between the callback and the disposal code as Henk Holterman suggested below, but I don't want to do this unless absolutely necessary.
推荐答案
使用此代码
timer = new Timer( state => {
// simulate some work that takes ten seconds
Thread.Sleep( tickInterval * 10 );
// when the work is done, schedule the next callback in one second
timer.Change( tickInterval, Timeout.Infinite );
},
null,
tickInterval, // first callback in one second
Timeout.Infinite );
几乎可以肯定的是,您将在计时器处于睡眠状态时对其进行处置.
it is almost certain that you will Dispose the timer while it is sleeping.
您必须保护Sleep()之后的代码,才能检测到Dispose计时器.由于没有IsDisposed属性,因此快速而肮脏的 static bool stop = false;
可能会成功.
You will have to safeguard the code after Sleep() to detect a Disposed timer. Since there is no IsDisposed property a quick and dirty static bool stopping = false;
might do the trick.
这篇关于如何优雅地停止System.Threading.Timer?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!