Windows中的等待计时器问题(timeSetEvent和CreateTimerQueueTimer)

时间:2010-03-25 13:41:51

标签: c# timer

我的应用程序需要高分辨率(超过1毫秒)的时序。 Windows中的等待定时器是(或可以制作)精确到毫秒,但如果我需要35.7142857141毫秒的精确周期,即使是36 ms周期的等待定时器也会快速失去同步。

我对这个问题的“解决方案”(具有讽刺意义的是因为它不能正常工作)是使用一系列一次性定时器,我使用每个定时器的到期来调用下一个定时器。通常这样的过程会随着时间的推移而出现累积误差,但是在每个定时器回调中,我检查当前时间(使用System.Diagnostics.Stopwatch)并使用它来计算下一个定时器的周期需要(所以如果一个计时器恰好迟到了,下一个计时器会自动缩短一段时间来补偿。

这可以按预期工作,除了可能在10-15秒后计时器系统似乎陷入困境,并且这里和那里的一些计时器回调迟到了25到100毫秒。几秒钟之后,问题消失了,一切都再次平稳运行10-15秒,然后再次出现口吃。

由于我使用Stopwatch来设置每个定时器周期,我还使用它来监控每个定时器回调的到达时间。在平稳运行期间,大多数(可能95%)的间隔是35或36毫秒,没有间隔距离预期的35.7142857143超过5毫秒。

在“毛刺”延伸期间,间隔的分布几乎完全相同,只是非常小的数量异常大(一个超过60毫秒,一个或两个超过100毫秒,可能是一个3秒的伸展) )。这种口吃非常明显,如果可能的话,这就是我想要解决的问题。

对于高分辨率计时器,我使用了来自timeSetEvent()的非常古老的winmm.dll多媒体计时器。为了解决这个问题,我转而使用CreateTimerQueueTimer(以及timeBeginPeriod来设置高分辨率),但我看到两个计时器机制都存在同样的问题。我已经尝试使用CreateTimerQueueTimer的各种标志进行试验,这些标志决定了计时器运行的哪个线程,但无论如何都会出现口吃。

这只是以这种方式使用定时器的基本问题(即使用每个单次定时器来调用下一个)?如果是这样,我有其他选择吗?我正在考虑的一件事是确定在我需要重置定时器之前,连续1毫秒精度的滴答将使我保持在任意精度限制内。所以,例如,如果我想要一个35.71428周期,我可以让一个36毫秒的计时器在它关闭前经过15次5毫秒,然后杀死它并开始一个新的计时器。

2 个答案:

答案 0 :(得分:3)

鉴于.NET的局限性,我认为你有一个很好的方法。您的流程优先级是多少?我认为它需要高于正常水平以避免其他进程执行磁盘活动。

我同意Henk的观点,即.NET框架不是最好的解决方案。如果发生垃圾收集,可能需要一段时间来释放对象,压缩堆等等。

您使用的操作系统是什么?我也同意Henk的观点,即实时操作系统是最佳解决方案。根据我的阅读,Windows CE有资格作为实时操作系统,但我无法进一步评论。

答案 1 :(得分:1)

定时器并不便宜,通过使用1毫秒的定时器接近35.7的定时器,你正在吃掉你的边缘。我认为你可能处于PC本身可以达到的极限 我会选择更长时间的计时器(35或36)并使用秒表计时器进行校正。

并且引起一些争议,我不太确定.NET框架是最适合这种任务的平台。您是否想过GC如何满足您的需求?