如何优雅地停止System.Threading.Timer? [英] How do I gracefully stop a System.Threading.Timer?

查看:51
本文介绍了如何优雅地停止System.Threading.Timer?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个用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:

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

The timer is not disposed until all currently queued callbacks have completed.

看来文档中的这一说法可能不正确.有人可以验证吗?

我知道我可以通过在回调和处理代码之间添加一些信号来解决该问题,如下面的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?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆