2

我正在开发一个启动 System.Threading.Timer 的应用程序,它对串行端口进行一些相当快速的读/写(每 100 毫秒)。计时器的回调方法如下所示:-

if (_timerTaskRunning)
{
    Debug.WriteLine("still running");
    return;
}

_timerTaskRunning = true;

... do the serial write/read here ...

_timerTaskRunning = false;

_timerTaskRunning标志是一种保障措施,以确保在前一个计时器“周期”尚未完成时委托不会运行,即它花费的时间超过 100 毫秒。

当我第一次启动应用程序时,我会从if语句中看到大约十几个调试消息。然后它会稳定下来,但我会在 7 或 8 秒后看到另一组消息。它再次稳定下来,每隔一段时间我就会看到一组消息以不同的数量出现。

我假设第一组消息是由于应用程序仍在启动、对象/UI 初始化等原因导致计时器委托运行缓慢引起的,而后续消息可能是由垃圾收集每隔一段时间启动并减慢引起的事情下来了?这不是串行端口,因为我看到“模拟”串行端口的行为相同。

我尝试将计时器的第一次运行延迟几秒钟,但这没有什么区别 - 在计时器启动后的第一秒左右,我仍然收到一批调试消息。跳过一些计时器任务并不是世界末日,但知道可能导致它们的原因会很有趣。我可以做些什么来进一步调查原因,例如 perfmon 是否可以说明问题?我以前没用过,你会推荐哪些柜台?

4

2 回答 2

3

听起来你有一个可重入问题。基本上,由于竞争条件,您的 _timerTaskRunning 可能无法起到保护作用。

  1. 使用System.Timers.Timer而不是 System.Threading.Timer
  2. 将 Timer.AutoReset 设置为 false。这将解决您令人着迷的问题,因为在您明确想要它之前它不会给您回电。
  3. 当您需要再次启动计时器时,请在计时器上调用 Start()(您可能需要调整间隔以考虑执行时间)

如果您有多个可以调用 start 的线程,则需要同步对它的调用。

于 2012-06-26T15:43:59.967 回答
2

_timerTaskRunning得到了几个线程的更新。您需要使用锁定使其成为线程安全的。

但是,我根本不会使用计时器。我在这里实现了一个非重用计时器。它使用AutoResetEvent带有超时功能的 WaitOne 来确保不可重入。

于 2012-06-26T15:38:58.833 回答