我试图每1毫秒调用一个函数。 问题是,我喜欢用windows做这个。 所以我尝试了multimediatimer API。
资源
idTimer = timeSetEvent( 1, 0, TimerProc, 0, TIME_PERIODIC|TIME_CALLBACK_FUNCTION );
我的结果是,大部分时间1毫秒是好的,但有时我得到了双倍的时间。 看到1.95ms左右的小颠簸multimediatimerHistogram http://img.zgserver.com/c%2B%2B/www.freeimagehosting.net
我的第一个想法是,也许我的方法运行时间太长。 但是我已经测量过了,事实并非如此。
我的下一个尝试是使用queud定时器API
hTimerQueue = CreateTimerQueue(); if(hTimerQueue == NULL) { printf("Error creating queue: 0x%x\n", GetLastError()); } BOOL res = CreateTimerQueueTimer( &hTimer, hTimerQueue, TimerProc, NULL, 0, 1, // 1ms WT_EXECUTEDEFAULT);
但结果并不如预期。 现在我大部分时间都是2 ms周期。 queuedTimer http://img.zgserver.com/c%2B%2B/www.freeimagehosting.net
为了衡量我使用QueryPerformanceCounter和QueryPerformanceFrequency方法的时间。
所以现在我的问题是,如果有人在Windows下遇到类似的问题,甚至可能find一个解决scheme?
谢谢。
不用去实时的操作系统,你不能期望每 1毫秒调用一次你的函数。
在不是实时操作系统的Windows上(对于Linux来说它是相似的),以微秒精度重复读取当前时间的程序,并且在直方图中存储连续差异的程序具有> 10ms的非空的bin! 这意味着有时你会有2毫秒,但你也可以获得更多的电话。
对NtQueryTimerResolution()
调用NtQueryTimerResolution()
返回一个值。 在你的情况下,实际的分辨率几乎肯定是0.9765625毫秒。 这正是你在第一个情节展示的。 大约1.95ms的第二次事件更准确地说是Sleep(1)
= 1.9531ms = 2×0.9765625ms
我猜中断周期接近1ms(0.9765625)。
现在麻烦就开始了:计时器在所需的延时结束时发出信号。
假设实际分辨率设置为0.9765625,系统的中断心跳将运行在0.9765625 ms周期或1024 Hz,并且以1 ms的期望延迟进行Sleep
呼叫。 有两种情况需要考虑:
所以结果很大程度上取决于通话的时间,因此您可以观察到0.98ms的事件以及1.95ms的事件。
编辑:使用CreateTimerQueueTimer
会将观察到的延迟推到1.95,因为计时器滴答(中断周期)是0.9765625毫秒。 在第一次发生中断时,所需的持续时间1 ms没有完全超时,因此TimerProc
只会在第二次中断后触发(2 x 0.9765625 ms = 1.953125 ms> 1 ms)。 因此,queueTimer图显示在1.953125 ms的峰值。
注意:此行为强烈依赖于底层硬件。
更多细节可以在Windows时间戳项目中找到
您可以尝试在退出前在程序开始和timeEndPeriod(1)
处运行timeBeginPeriod(1) 。 这可能会提高定时器的精度。