定时器不会死(已经!)

时间:2010-08-08 12:39:32

标签: c#

一段时间以来,我一直在经历这种经常性的噩梦(阅读 - 申请中的错误)。出于某种原因,某个计时器在我停止后会继续发送“经过的”事件,即使事件本身 ,计时器“承认”已被禁用!看看这个:

//Timer is created in Class' Constructor. Class is not static.
public PDAAccess ()
{
  ConnectionTimeoutChecker = new System.Timers.Timer(1000);
  ConnectionTimeoutChecker.Elapsed += new System.Timers.ElapsedEventHandler(ConnectionTimeoutChecker_Elapsed);
}

void ConnectionTimeoutChecker_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{ //_DeviceConTimeout eventually reaches A LOT MORE than 10.
  if (_DeviceConTimeout > 10)
  {
    ConnectionTimeoutChecker.Stop(); //This is invoked but the timer DOES NOT STOP.
    if (OnDeviceSyncTimeout != null) OnDeviceSyncTimeout(this, null); //This gets fired all the time.
  }
  _DeviceConTimeout++; //This keeps increasing and increasing.
  //Worth mentioning: sender = Timer, sender.Enabled = false (!) so then why is this executing?
}

至于我在哪里开始它:我在一个地方开始它,我在那里放了一个断点,它不会执行多次。在你问之前:没有涉及多个线程。我在这个应用程序中使用线程,但是:计时器不是在线程中创建的,也不是类。

然而.Stop();执行100次,计时器仍然不会停止。

我在这里完全不知所措。这种行为对我来说太奇怪了,它让我感到尴尬,我可能会遗漏一些非常明显的东西。有时写这样的帖子可以帮助我在点击提交按钮之前找出问题(我们都知道“向第三方解释”效果)。但它还没有击中我,所以我会按下按钮......看看你看到了什么:: - D。

2 个答案:

答案 0 :(得分:1)

在黑暗中拍摄:或许以某种方式调用OnDeviceSyncTimeout()会间接导致计时器重新激活?我知道你说它只是在一个地方开始,但我不确定你怎么能这么肯定。

答案 1 :(得分:0)

嗯,这对您发布的代码段没有多大意义。但是像这样的非同寻常的问题需要特别的解释。

System.Timers.Timer类是一个可怕的计时器。您看到的条件是,在计时器停止时调用Elapsed事件,在大多数情况下都是不可避免的。问题是它通过使用ThreadPool.QueueUserWorkItem()引发了Elapsed事件。该线程受线程池调度程序和Windows线程调度程序的变幻莫测的影响。 QUWI 保证线程立即运行。相反,线程进入“准备运行”状态的队列。 TP调度程序仅在认为正确运行线程的时间时才将其从该队列中删除。对于一个人而言,如果已经有多个线程在运行,那么它将被卡住一段时间,因为你的机器有CPU内核。仅当线程未完成时才允许运行更多线程。这需要一段时间,这些调度决策每秒只运行两次。

Windows线程调度程序也起作用。当机器加载时,有许多线程准备好运行,那么在经过的线程转弯之前可能需要一段时间。对这个问题特别讨厌的是,这样的比赛在很大程度上依赖于你的程序或机器上发生的其他事情。在你的开发机器上运行正常,当Elapsed事件最终设法运行时,即使计时器很久以前停止了,也会在生产中出现不可预测的故障。

另请注意,这可能会增加。你特别容易受到攻击,因为你在Elapsed事件中停止了计时器。当TP线程无法进行调度时,定时器只是一直调用QUWI,添加更多TP线程,而代码无法停止计时器。

嗯,猜测,但确实解释了这个问题。 UI库中的同步计时器或System.Thread.Timer应该修复它。试着使用后者的单拍版本。超时是固定的时间,不应该被计算在内。