0

我正在使用两个实例System.Threading.Timer来触发定期重复的 2 个任务。

我的问题是:如果计时器被禁用,但在那个时间点,这个计时器正在线程上执行它的回调,那么Main方法会退出,还是会等待执行的回调完成?

在下面的代码中,Method1RunCount使用 lock 语句进行同步读写(这部分代码下面没有显示)。每次运行结束时timer1递增1 的回调。Method1RunCount

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;
         }
     }
 }
4

2 回答 2

2

这种代码往往会意外工作,计时器的周期足够大,可以避免 Method1RunCount 变量上的线程竞争。使周期更小,主线程根本看不到值“4”存在真正的危险。当处理器负载很重并且主线程没有被安排一段时间时,几率会大大降低。当主线程等待处理器时,计时器的回调可以执行多次。完成缺失值递增到 4。请注意lock语句实际上并没有阻止这种情况,它没有被主线程锁定,因为它可能正在休眠。

您也无法合理猜测 Method2 的运行频率。不仅因为它具有完全不同的计时器周期,而且从根本上说因为它根本不同步到 Method1 或 Main 方法执行。

您通常会在 Method1结束时增加 Method1RunCount。这并不能保证 Method1 不会被中止。它在线程池线程上运行,它们的 Thread.IsBackground 属性始终设置为 true。因此,当主线程退出时,CLR 很容易中止它们。这再一次倾向于不会偶然引起问题。

如果 Method1 恰好执行 4 次是绝对必要的,那么确保这一点的简单方法是让 Method1 进行计数。在方法内调用 Timer.Change() 很好。使用 AutoResetEvent 之类的类让主线程知道它。现在不再需要睡眠了。您仍然需要一个锁来确保 Method1 在执行时不能被重新输入。了解线程同步错误的一个好方法是当您看到自己使用 Thread.Sleep() 时。

于 2013-06-01T13:45:59.440 回答
0

System.Threading.Timerhttp://msdn.microsoft.com/en-us/library/system.threading.timer.aspx)上的文档:

当不再需要计时器时,使用 Dispose 方法释放计时器持有的资源。请注意,调用 Dispose() 方法重载后可能会发生回调,因为计时器将回调排队以供线程池线程执行。您可以使用 Dispose(WaitHandle) 方法重载来等待所有回调完成。

于 2013-06-01T07:37:11.303 回答