我正在使用System.Threading.Timer的两个实例来触发定期重复的2个任务。
我的问题是:如果计时器被禁用但在此时间点此计时器正在线程上执行其回调,那么Main方法将退出或者它将等待执行的回调到完成?
在下面的代码中,Method1RunCount使用lock语句进行读写同步(这部分代码未在下面显示)。对于timer1的回调,在每次运行结束时将Method1RunCount递增1。
static void Main(string[] args)
{
TimerCallback callback1 = Method1;
System.Threading.Timer timer1 = new System.Threading.Timer(callback1,null,0, 90000);
TimerCallback callback2 = Method2;
System.Threading.Timer timer2 = new System.Threading.Timer(callback2, null, 0, 60000);
while (true)
{
System.Threading.Thread.Sleep(250);
if (Method1RunCount == 4)
{
//DISABLE the TIMERS
timer1.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
timer2.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
break;
}
}
}
答案 0 :(得分:2)
这种代码往往是偶然的,定时器的周期足够大,以避免Method1RunCount变量上的线程竞争。缩短期限,主要线程不会看到价值" 4"一点都不当处理器负载很重且主线程没有安排好时,可能性会大大降低。然后,当主线程正在等待处理器时,计时器的回调可以执行多次。完成丢失值增加到4.注意 lock 语句实际上不会阻止它,它不会被主线程锁定,因为它可能正在睡眠。
对于Method2运行的频率,您也无法做出合理的猜测。不仅因为它具有完全不同的计时器周期,而且基本上是因为它根本不与Method1或Main方法执行同步。
您通常会在Method1的 end 处增加Method1RunCount。但这并不能保证Method1不会被中止。它在线程池线程上运行,它们的Thread.IsBackground属性始终设置为true。因此,当主线程退出时,CLR将很快中止它们。这也不会偶然导致问题。
如果Method1执行正好4次绝对必要,那么确保这样做的简单方法就是让Method1进行计数。在方法中调用Timer.Change()很好。使用类似AutoResetEvent的类让主线程知道它。现在不再需要睡眠了。您仍需要锁定以确保在执行时无法重新输入Method1。当你看到自己使用Thread.Sleep()时,知道你正在获得错误的线程同步的好方法。
答案 1 :(得分:0)
来自System.Threading.Timer
(http://msdn.microsoft.com/en-us/library/system.threading.timer.aspx)上的文档:
当不再需要计时器时,使用Dispose方法释放 计时器持有的资源。请注意,回调可能发生在 已调用Dispose()方法重载,因为定时器队列 线程池线程执行的回调。你可以使用 Dispose(WaitHandle)方法重载等待直到所有回调都有 完成。