2017-07-06 51 views
-1

我试图与一个稳定的循环时间(例如20毫秒)执行的方法。我目前的做法是使用std::thread创建线程。这个线程我做了以下(伪)内部:稳定的循环时间

while(true) 
{ 
    tStart = GetCurrentTime(); 
    ExecuteMethod(); 
    tEnd = GetCurrentTime(); 

    actualCycleTime = tEnd - tStart; 
    SleepFor(DesiredCycleTime - actualCycleTime); 
} 

时间测量和睡觉我用std::chronostd::steady_clockstd::thread::sleep_for)。

的问题是,我的循环不会在预期的稳定运行为20ms。相反,我的循环时间在20到60毫秒之间。我的猜测是,这是由Windows调度程序造成的。

有没有更好的方式来实现稳定的周期时间(忙等待,等等)?

+0

您正在使用重复的相对时间,这会在确定实际循环时间和设置所需循环时间之间容易受到竞速条件的影响。您需要一个具有所需周期时间的外部控制的周期性触发器。 – Yunnosch

+0

您可能想要查看https://stackoverflow.com/questions/2904887/sub-millisecond-precision-timing-in-c-or-c/2905082#2905082 – jodag

+0

timeSetEvent与timeBeginPeriod一起使用时相当可靠。 MSDN说它已经过时,但你应该使用https://msdn.microsoft.com/en-us/library/ms682485(v=vs.85).aspx我没有任何经验,所以我不能说它有多可靠或精确。 –

回答

2

你可以使用一个计时器事件。如果你需要一个非常坚固的时钟,你需要提高你的优先级到最大。此代码将为您提供用户模式应用程序的最佳性能。为了清楚起见,我省略了通常的错误检查,但是我标记了应该检查的调用。如有疑问,请咨询MSDN。

的Windows计时器的分辨率被限制在一个全球性的时间片Windows使用线程之间进行切换。在现代CPU上,这个值通常为2-5ms。在较旧的CPU上,这个值是10-15ms。您可以通过调用timeBeginPeriod()来控制此全局设置 。这会影响中断的精度。

// use this event to exit the loop, by calling SetEvent(hExitEvent). 
HANDLE hExitEvent = CreateEvent(NULL, NULL, FALSE, NULL); 

void RealTimeLoop() 
{ 
    // You may want to raise the process priority... 
    HANDLE hProcess = GetCurrentProcess();      // never fails 
    SetPriorityClass(hProcess, REALTIME_PRIORITY_CLASS); 

    // setting the priority is critical. 
    HANDLE hThread = GetCurrentThread();       // never fails 
    SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL); // could fail 

    timeBeginPeriod(1);           // could fail 

    HANDLE hTimer = CreateWaitableTimer(NULL, FALSE, NULL);  // could fail 

    // could also set a call back here, but I've never tried it. 
    LARGE_INTEGER dueTime = {}; 
    SetWaitableTimer(hTimer, &dueTime, 20, NULL, NULL, FALSE); // could fail 

    HANDLE ah[2] = { hExitEvent, hTimer }; 
    bool exitLoop = false; 

    while(!exitLoop) 
    { 
     switch (WaitForMultipleObjects(2, ah, FALSE, INFINITE)) 
     { 
      default: // error would arrive here 
      case 0: exitLoop = true; break; 
      case 1: ExecuteMethod(); break; 
     } 
    } 
    timeEndPeriod(1); 
    CloseHandle(hTimer); 
    CloseHandle(hThread); 
    CloseHandle(hProcess); 
}