Windows队列计时器的限制

时间:2014-11-24 22:10:30

标签: visual-c++ windows-7 timer high-resolution periodic-task

我正在实现一个计时器,需要它每50毫秒左右运行一次,并希望分辨率为1毫秒或更短。我开始阅读这两篇文章:

http://www.codeproject.com/Articles/1236/Timers-Tutorial

http://www.virtualdub.org/blog/pivot/entry.php?id=272

奇怪的是,他们似乎互相矛盾。有人说队列计时器有利于高分辨率,其他帖子来自Windows 7系统,显示分辨率约为15毫秒(对我的应用来说还不够好)。

所以我对我的系统进行了测试(Win7 64bit i7-4770 CPU @ 3.4 Ghz)。我开始的时间是50毫秒,这就是我所看到的(从左边开始的时间,右边的执行之间的差距;全部以毫秒为单位):

150   50.00
200   50.01
250   50.00
...
450   49.93
500   50.00
550   50.03
...
2250  50.10
2300  50.01

我发现最大误差大约为100 us,平均误差可能在30左右左右。这让我很开心。

所以我开始放弃这段时间,看看它变得不可靠。一旦我减少了周期< = 5ms,我就开始看到不好的结果。

在5毫秒的时间内,每隔几秒就会看到一些时段在3到6毫秒之间跳跃并不罕见。如果我将周期缩短到1ms,可以看到5到10到40毫秒的周期。我认为跳跃到40ms可能是因为我正在将内容打印到屏幕上,我不知道。

这是我的计时器回调代码:

VOID CALLBACK timer_execute(PVOID p_parameter, 
   BOOLEAN p_timer_or_wait_fired)
{ 
   LARGE_INTEGER l_now_tick;

   QueryPerformanceCounter(&l_now_tick);

   double now = ((l_now_tick.QuadPart - d_start.QuadPart) * 1000000) / d_frequency.QuadPart;
   double us = ((l_now_tick.QuadPart - d_last_tick.QuadPart) * 1000000) / d_frequency.QuadPart;

   //printf("\n%.0f\t%.2f", now / 1000.0f, ms / 1000.0f);

   if (us > 2000 ||
       us < 100)
   {
      printf("\n%.2f", us / 1000.0f);
   }

   d_last_tick = l_now_tick;
}

无论如何,只要你以100hz或更慢的速度执行,它看起来好像排队定时器是非常好的工具。我链接到的第二篇文章中发布了不良结果(精度为15ms左右)可能是由于CPU速度较慢或配置不同?

我想知道我是否可以在多台机器上获得这种性能(所有这些都比运行64位Win7的机器快或快)?另外,我注意到如果你的回调在经过一段时间之前没有退出,操作系统会把另一个线程放在那里。这可能是显而易见的,但它在任何文档中都没有突出显示,并且对客户端代码有重大影响。

2 个答案:

答案 0 :(得分:2)

Windows默认计时器分辨率为15.625 ms。这是您观察到的粒度。 但是,可以按照MSDN:Obtaining and Setting Timer Resolution的描述修改系统计时器分辨率。这允许在大多数情况下将粒度减小到大约1ms 平台。 This SO答案公开了如何获得当前的系统计时器分辨率。

隐藏功能NtSetTimerResolution(...)甚至允许在平台支持时将定时器分辨率设置为0.5 ms。请参阅this SO回答问题“如何将定时器分辨率设置为0.5毫秒?

...一个不同的配置? 这取决于底层硬件和操作系统版本。使用上面提到的太阳镜检查定时器分辨率。

...一切都比运行64位Win7的机器快或快? 是的你可以。但是,也允许其他应用程序设置定时器分辨率。谷歌Chrome是一个众所周知的例子。这样的其他应用程序也可以仅临时改变计时器分辨率。因此,您永远不能依赖计时器分辨率 跨平台/时间不变。 确保定时器分辨率的唯一方法 由您的应用程序控制的是自己将计时器粒度设置为最小1毫秒(0.5毫秒)。

注意:减少系统计时器粒度会导致系统中断频率增加。它减少了线程量子(时间片)并增加了功耗。

答案 1 :(得分:0)

我认为差异是因为系统中使用的资源管理。我刚刚在我的操作系统类的演示文稿中了解到这一点。由于有许多进程正在运行,因此当时间太短时,可能无法足够快地对进程进行排队。另一方面,当它有更多的时间时,进程就会及时排队,并且还与优先级有关。我希望这有点帮助。