2016-03-02 37 views
9

讓我們下面的一段代碼,簡單地衡量std::this_thread::sleep_for調用20ms的持續時間: 的std :: this_thread :: sleep_for睡覺短於​​預期VS2015

#include <iostream> 
#include <chrono> 
#include <thread> 

using namespace std; 
using namespace std::chrono; 

int main() 
{ 
    for (int i = 0; i < 20; i++) 
    { 
     auto start = steady_clock::now(); 
     this_thread::sleep_for(milliseconds(20)); 
     auto end = steady_clock::now(); 
     duration<double, milli> elapsed = end - start; 
     cout << "Waited " << elapsed.count() << " ms\n"; 
    } 
} 

運行時與工具套件編譯V120 (VS2013的),我得到的結果不如預期,即:

Waited 20.0026 ms 
Waited 20.0025 ms 
Waited 20.0025 ms 
Waited 20.0026 ms 
Waited 20.0025 ms 
Waited 20.0025 ms 
Waited 20.0026 ms 
Waited 20.0025 ms 
Waited 20.0025 ms 
Waited 20.0026 ms 

但與VS2015的工具集V140運行,結果多少有些令人吃驚和不尊重來自msdncppreference.com承諾說明(即sleep_for阻止執行當前線程至少指定的sleep_duration)。它們如下:

Waited 19.7793 ms 
Waited 19.9415 ms 
Waited 19.6056 ms 
Waited 19.9687 ms 
Waited 19.608 ms 
Waited 19.589 ms 
Waited 20.5435 ms 
Waited 19.5669 ms 
Waited 19.6802 ms 
Waited 19.5381 ms 

怎樣的可能,以及如何可以讓VS2015的sleep_for只要預期至少睡覺?

的問候,的Dawid

編輯:

按照要求那些是我的設置和操作系統的詳細信息:
OS

  • Windows 7專業版64位

  • 視覺工作室:2010旗艦版,2013社區,2015年專業與更新1個

編譯器設置

  • 爲Win32控制檯應用程序的默認設置,

  • 任何調試和發佈配置,

  • 任何x86和x64目標平臺archit ectures

+0

在早期喚醒的情況下,我通常在循環中使用'sleep_until()'。我認爲早期喚醒不應該發生,但在GCC Linux上,至少,每當進程收到信號時(顯然這裏不是你的問題),提早醒來似乎就會發生。 – Galik

+0

我在本地看不到相同的結果或例如在http://rextester.com/l/cpp_online_compiler_visual(它也使用VS2015)。考慮添加更多有關您的確切編譯器設置,目標架構,主機操作系統,機器規格等的信息。 – Yirkha

+0

@Yirkha:我在描述中添加了有關我的條件的更多詳細信息。至於你的結果 - 它看起來像在我的系統中尋找一點點差異。 – dawid

回答

8

在VS2015的sleep_for()方法實現已經包含圍繞Sleep()系統調用一個循環,所以任何虛假喚醒不會影響它 - 看到_Thrd_sleep()VC\crt\src\stl\cthread.c


你的問題的原因是最有可能的事實是sleep_for(),並sleep_until()它調用裏面,使用chrono::system_clock計算時間等待,但要測量使用chrono::steady_clock時期。

這兩個計時器可能具有相同的精度,但不一定相同的精度。那麼可能發生system_clock滯後一點,而steady_clock已經提前幾微秒,並且使用system_clock計算的等待實際上比請求的要短。


在這種情況下,準確,steady_clock使用QueryPerformanceCounter()(見VC\include\chrono,搜索struct steady_clock),所以這將是非常準確和精確的執行,因爲這是首選的Windows API來使用精確的時間測量。

system_clock使用GetSystemTimePreciseAsFileTime()(見VC\include\chrono,搜索struct system_clock),並承諾「的精度的最高水平(< 1微秒)」也可以實現。唉,正如MSDN頁面所說,這個API只支持Windows 8以上版本,並且您在Windows 7機器上只能以ms精度與舊的GetSystemTimeAsFileTime()卡住。這很可能是您測量錯誤的結果。


根據您的具體使用情況,您可能會以不同的方式處理這個問題。我會考慮忽略這個小錯誤,因爲暫停線程並等待調度程序將其喚醒並不會非常準確。

+0

看起來事情的原因來自'sleep_for'使用的時鐘和我的測量方法的差異。檢查我是否已經暫時將測量時鐘更改爲'system_clock',並且結果與預期一致。然而,由於你沒有在本地再現這種效果,所以我覺得你的'sleep_for'使用'steady_clock',這是相當可疑的。如果是這樣,如果它依賴於操作系統的條件,有沒有辦法讓'sleep_for'使用'steady_clock'? – dawid

+0

這是在CRT內部實現的,甚至不通過'chrono'界面,所以你將不得不重建它 - 所以不。 Windows升級> = 8會解決所有問題,或者您可以在受影響的平臺上添加少量的持續時間(以使「等待> = X」的要求始終爲真)。 – Yirkha

2

雖然標準說實現應該使用的*_for計時功能的steady_clock,這不是必需的。如果使用非穩態時鐘,則時鐘調整可能導致睡眠時間縮短。在這種情況下,定時功能可能不會提供如標準所述的有用功能

但是,您的結果顯示持續下降,我認爲這可能表明行爲不符合標準。

您可以通過使用自己選擇的時鐘自己測量時間並在循環中休眠,直到目標時間過去,從而解決此類問題。

相關問題