我尝试每隔1 ms调用一次函数。问题是,我喜欢用windows做这个。所以我尝试了多媒体时间API。
来源
idTimer = timeSetEvent(
1,
0,
TimerProc,
0,
TIME_PERIODIC|TIME_CALLBACK_FUNCTION );
我的结果是大部分时间1毫秒都没问题,但有时我会得到双倍期。看到1.95ms左右的小凹凸 multimediatimerHistogram http://www.freeimagehosting.net/uploads/8b78f2fa6d.png
我的第一个想法是,也许我的方法运行时间过长。但我已经测量过了,情况并非如此。
我的下一次尝试是使用带有
的queud计时器APIhTimerQueue = 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毫秒的周期时间。 queuedTimer http://www.freeimagehosting.net/uploads/2a46259a15.png
为了测量时间,我使用了QueryPerformanceCounter和QueryPerformanceFrequency方法。
所以现在我的问题是,是否有人在Windows下遇到过类似的问题,甚至可能找到解决方案?
感谢。
答案 0 :(得分:5)
如果没有实时操作系统, 希望您的功能名为每 1毫秒。
在不是实时操作系统的Windows上(对于Linux来说,它类似),一个以微秒精度重复读取当前时间并在直方图中存储连续差异的程序有一个非空的bin> 10女士!这意味着有时您将有2毫秒,但您也可以在通话之间获得更多。
答案 1 :(得分:1)
对NtQueryTimerResolution()
的调用将返回 ActualResolution 的值。在您的情况下,实际分辨率几乎肯定是0.9765625毫秒。这正是您在第一个图中显示的内容。
大约1.95 ms的第二次出现更精确Sleep(1)
= 1.9531 ms = 2 x 0.9765625 ms
我猜中断周期接近1ms(0.9765625)。
现在麻烦开始了:当所需的延迟到期时,定时器发出信号。
假设 ActualResolution 设置为0.9765625,系统的中断心跳将以0.9765625 ms周期或1024 Hz运行,并且调用Sleep
时所需的延迟为1女士。有两种情况需要考虑:
因此,结果很大程度上取决于调用的时间,因此您可能会观察到0.98ms事件以及1.95ms事件。
编辑:使用CreateTimerQueueTimer
会将观察到的延迟推至1.95,因为计时器滴答(中断周期)为0.9765625 ms。在中断的第一次出现时,所请求的1ms的持续时间尚未完全到期,因此TimerProc
仅在第二次中断(2×0.9765625ms = 1.953125ms> 1ms)之后被触发。因此,queueTimer图显示峰值为1.953125 ms。
注意:此行为很大程度上取决于底层硬件。
找到更多详情答案 2 :(得分:0)
您可以尝试在程序启动时运行timeBeginPeriod(1)并在退出前timeEndPeriod(1)
运行。这个可能可以提高计时器的精确度。