代码之家  ›  专栏  ›  技术社区  ›  schoetbi

如何在WinXP下获得精确的1毫秒计时器计时

  •  9
  • schoetbi  · 技术社区  · 14 年前

    我试着每1毫秒调用一个函数。问题是,我喜欢用Windows来实现。所以我尝试了多中介时间API。

    多中介时间API

    来源

    idTimer = timeSetEvent( 
         1, 
         0,
         TimerProc, 
         0, 
         TIME_PERIODIC|TIME_CALLBACK_FUNCTION ); 
    

    我的结果是,大多数时间1毫秒是正常的,但有时我得到了双周期。看到1.95毫秒左右的小突起 multimediatimerHistogram http://www.freeimagehosting.net/uploads/8b78f2fa6d.png

    我的第一个想法是也许我的方法运行得太久了。但我已经测量过了,事实并非如此。

    排队计时器API

    我的下一次尝试是将Queud Timers 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毫秒的循环时间。 queuedTimer http://www.freeimagehosting.net/uploads/2a46259a15.png

    测量

    为了测量使用queryPerformanceCounter和queryPerformanceFrequency方法的次数。

    问题

    所以现在我的问题是,是否有人在Windows下遇到类似的问题,甚至可能找到解决方案?

    谢谢。

    3 回复  |  直到 11 年前
        1
  •  5
  •   Didier Trosset    14 年前

    不使用实时操作系统, 不能 希望调用函数 每一个 1毫秒。

    在不是实时操作系统的Windows上(对于Linux类似),一个以微秒精度重复读取当前时间并将连续差异存储在柱状图中的程序具有一个非空的bin,持续时间为10毫秒!这意味着有时你会有2毫秒的通话时间,但你也可以在通话中获得更多的信息。

        2
  •  1
  •   Arno    11 年前

    对…的呼唤 NtQueryTimerResolution() 将返回的值 实际分辨率 . 在您的例子中,实际分辨率几乎可以确定为0.9765625 ms。这正是您在第一个图中显示的。 第二次发生约1.95毫秒更准确。 Sleep(1) =1.9531 ms=2 x 0.9765625 ms

    我猜中断时间大约在1毫秒(0.9765625)左右。

    现在问题开始了:定时器会在所需延迟到期时发出信号。

    实际分辨率 设置为0.9765625时,系统的中断心跳将以0.9765625 ms或1024 Hz的周期运行,并调用 Sleep 以1 ms的期望延迟进行。要查看两种情况:

    1. 在下一次中断前,呼叫被发出<1毫秒(_)T。下一个中断将不会确认所需的时间段已过期。只有以下中断才会导致调用返回。由此产生的睡眠延迟将是t+0.9765625 ms。
    2. 在下一个中断之前,呼叫被发出>=1毫秒(_)T。下一个中断将强制调用返回。由此造成的睡眠延迟将是。

    因此,结果很大程度上取决于通话的时间,因此您可以观察到0.98ms事件以及1.95ms事件。

    编辑: 使用 CreateTimerQueueTimer 会将观察到的延迟推至1.95,因为计时器刻度(中断周期)为0.9765625 ms。在第一次出现中断时,请求的1 ms持续时间尚未完全过期,因此 TimerProc 仅在第二次中断后触发(2 x 0.9765625 ms=1.953125 ms>1 ms)。因此,排队计时器图显示1.953125 ms时的峰值。

    注意:此行为强烈依赖于底层硬件。

    有关更多详细信息,请访问 Windows Timestamp Project

        3
  •  0
  •   n0rd    14 年前

    你可以试着跑 timeBeginPeriod(1) 在节目开始时 timeEndPeriod(1) 在退出之前。这个 可能 可以提高定时器的精度。