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

标签 c# .net 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();

问题是当 waitHandle.WaitOne 阻塞时,我从回调线程上的 timer.Change 得到了一个 ObjectDisposedException。我做错了什么?

The documentation对于我正在使用的 Dispose 重载说:

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

编辑:看来文档中的此声明可能不正确。有人可以验证吗?

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

最佳答案

用这段代码

 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 );

几乎可以肯定的是,您将在定时器休眠时对其进行 Dispose。

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

关于c# - 如何优雅地停止 System.Threading.Timer?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12354883/

相关文章:

c# - 如何在Winform应用程序中限制父控件内的子控件?

java - 当调用 Timer.cancel() 时,运行由 java.util.Timer 启动的线程的行为是什么?

c# - 该属性是键的一部分,因此不能修改或标记为已修改(ForeignKey 不是键)

c# - 由 Directory.Delete() 引起的 WCF 安全异常

c# - 一般 Lambda 语法问题

java - 执行者没有运行所有线程。

c++ - BOOST::thread worker 同步,C++ 和 OpenCV

c# - WPF 列表和上下文菜单

c# - 通用接口(interface)问题

asp.net - 有关将 .NET Windows 窗体应用程序迁移到 Web 应用程序的指南