我在 CF 项目(Windows Embedded CE 6.0)、VS2005 C#、.NET 2.0 中使用 System.Threading.Timer。这个计时器是需要的,因为这样使用时不可能重入:
private System.Threading.Timer mainTimer;
private void MainForm_Load(object sender, EventArgs e)
{
// other initializations
mainTimer = new System.Threading.Timer(new TimerCallback(timerMain_Tick),
null, 100, Timeout.Infinite);
}
也就是说,使用了dueTime参数,但没有使用period。只要 period 为 Timeout.Infinite,计时器只会触发一次。通过检查表单的 InvokeRequired 属性使计时器成为线程安全的。请注意检查是否为空。它与我的问题有关,我很快就会回答。
private void timerMain_Tick(object stateInfo)
{
if (mainTimer != null)
{
if (this.InvokeRequired)
{
this.Invoke((ThreadStart)delegate
{
TimerProcess();
});
}
else
{
TimerProcess();
}
}
}
计时器必须在退出之前自行重新启动。
private void TimerProcess()
{
try
{
// do work here
}
finally
{
// retrigger
mainTimer.Change(mainTimerInterval, Timeout.Infinite);
}
}
我遇到的问题是优雅地停止这个该死的事情。
private void MainForm_Closing(object sender, CancelEventArgs e)
{
// shut down timer
mainTimer.Change(Timeout.Infinite, Timeout.Infinite);
mainTimer.Dispose();
mainTimer = null;
}
大约 10 次中的 3 次,无论如何都会触发计时器,并且我收到 Object Disposed 错误。计时器代码尝试在检查 null 之后调用计时器方法。我怀疑计时器触发了,并且它的线程在表单关闭时被挂起。我尝试了状态机枚举:
正常状态运行
Form_Closing 设置 Stopping 状态并在 Thread.Sleep() 循环中等待 Stopped 状态
Timer 看到 Stopping 并设置 Stopped 状态(而不是重新触发自身)
我遇到的问题是计时器线程不会抢占表单关闭方法,因此陷入无限循环。如何解决这个问题?请注意,在 CF 中,没有 Dispose(WaitHandle) 方法。