【发布时间】:2010-11-25 12:26:40
【问题描述】:
当您处理“原始”.net 计时器时,您可以传入一个等待句柄,以便在 Win32 计时器被销毁后调用,并且您可以假设您的回调不会被调用。 (并且计时器将被 GC 视为“死”)
如何使用 System.Timers.Timer 执行此操作?
【问题讨论】:
标签: .net multithreading timer dispose
当您处理“原始”.net 计时器时,您可以传入一个等待句柄,以便在 Win32 计时器被销毁后调用,并且您可以假设您的回调不会被调用。 (并且计时器将被 GC 视为“死”)
如何使用 System.Timers.Timer 执行此操作?
【问题讨论】:
标签: .net multithreading timer dispose
在调用 dispose 之前设置一个标志,并在您的 elapsed 处理程序中检查此标志。即使计时器确实触发了,该标志也会阻止任何关联的处理程序代码运行。您可以通过为计时器编写一个包装器来形式化这种模式。
确保您的标志被标记为 volatile,因为它将被不同的线程访问。
【讨论】:
由于 System.Timers.Timer 和 System.Windows.Forms.Timer 都使用 ThreadPool,它没有操作系统计时器的句柄,因此没有处理本地计时器资源 - 只是一个完整的线程。我不确定您是否可以捕获线程池正在回收的线程,但我可能错了。
您可以自己滚动(我还没有测试过,在 Dispose 中使用 ManualResetEvent 可能更有用):
void Run()
{
ManualResetEvent resetEvent = new ManualResetEvent(false);
System.Threading.Timer timer = new System.Threading.Timer(delegate { Console.WriteLine("Tick"); });
timer.Dispose(resetEvent);
MyTimer t = new MyTimer();
t.Interval = 1000;
t.Elapsed += delegate { t.Dispose(resetEvent); };
resetEvent.WaitOne();
}
public class MyTimer : System.Timers.Timer
{
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
}
public virtual void Dispose(WaitHandle handle)
{
handle.SafeWaitHandle.Close();
Dispose();
}
}
【讨论】:
Component.Dispose(disposing) 内部被调用,因此在调用 base.Dispose() 之前向 WaitHandle 发出信号,并使用它应该在之后触发的自定义 Dispose(WaitHandle)。