2017-07-06 80 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); 
}