3

关于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()方法后不会发生回调。我的猜测正确吗?

4

1 回答 1

2

其中一种方法是切换到System.Timers.Timer. 我在博客上写过:

http://netpl.blogspot.com/2010/05/systemwindowsformstimer-vs.html

(条目的第二部分)

于 2012-09-17T20:16:22.613 回答