如何优雅地停止System.Threading.Timer?

Wil*_*oss 15 .net c# multithreading

我有一个用C#实现的Windows服务,需要经常做一些工作.我已经使用System.Threading.Timer带有回调方法的方法来实现它,该方法负责安排下一个回调.我无法正常停止(即处理)计时器.这是一些简化的代码,您可以在控制台应用程序中运行,以说明我的问题:

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();
Run Code Online (Sandbox Code Playgroud)

问题是我在阻塞时ObjectDisposedExceptiontimer.Change回调线程获得了一个waitHandle.WaitOne.我究竟做错了什么?

Dispose我正在使用的重载文档说:

在完成所有当前排队的回调之前,不会释放计时器.

编辑:似乎文档中的此声明可能不正确.有人可以验证吗?

我知道我可以通过在回调和处理代码之间添加一些信号来解决这个问题,正如Henk Holterman在下面提到的那样,但除非绝对必要,否则我不想这样做.

Hen*_*man 11

有了这段代码

 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 );
Run Code Online (Sandbox Code Playgroud)

几乎可以肯定的是,你会在睡觉时处理掉计时器.

您必须在Sleep()之后保护代码以检测Disposed计时器.由于没有IsDisposed属性,快速而肮脏的static bool stopping = false;可能会成功.

  • 想知道是否短语"排队回调"字面上意味着可能有待处理但当前没有执行的额外回调,例如,根据定义,当前正在执行的回调是否未排队? (3认同)