关于System.Threading.Timer
类的文档指出:
请注意,调用 Dispose() 方法重载后可能会发生回调,因为计时器将回调排队以供线程池线程执行。
这意味着在调用Dispose()
方法之前安排的所有回调都必须完成。但是如何安排回调?下一次回调安排在什么时候?
假设我们创建了一个新的Timer
类实例,其有限周期等于P和有限到期时间等于D。回调的第一次执行将在D毫秒之后发生。随后的回调将在前一个回调开始的P毫秒后执行。编写代码示例,您将看到如果回调执行时间大于指定的周期P,则计时器将回调排队。
假设回调要备份文件上的一些数据:回调执行时间是备份执行时间,取决于必须写入文件的数据量,所以回调执行时间可能会超过指定的时间。在这种情况下,在当前备份结束时安排下一次备份更合适:为此,禁用周期性行为(通过将 period 设置为Timeout.Infinite
)并Change()
在回调结束时调用方法就足够了,如以下示例代码所示。
// some private fields
private readonly object syncRootForTimer = new object();
private Timer backupTimer = new Timer(BackupCallback, null, 10000, Timeout.Infinite);
private bool isTimerDisposed = false;
// it performs timer shutdown
public void Shutdown()
{
WaitHandle disposed = AutoResetEvent(false);
lock(syncRootForTimer)
{
backupTimer.Dispose(disposed);
isTimerDisposed = true;
}
WaitHandle.WaitAll(new WaitHandle[]{ disposed });
// ...
}
private void BackupCallback(object state)
{
// It performs the backup procedure...
// ...
lock(syncRootForTimer)
{
if (!isTimerDisposed)
backupTimer.Change(10000, Timeout.Infinite);
}
}
这样,似乎没有回调排队。我还注意到,Dispose(WaitHandle)
在最后一个计划之后(即在最后一次调用该方法之后Change()
)立即调用该方法,甚至没有执行最后一个计划,并且立即释放计时器。
我想我可以说禁用周期性行为并在回调执行结束时更改到期时间,计时器排队没有回调。这应该确保在调用Dispose()
方法后不会发生回调。我的猜测正确吗?