2016-03-02 17 views
9

に予想より短い眠るだけでは20msと呼ばれるstd::this_thread::sleep_forの継続時間を計測していること、のは、次のコードを持ってみましょう: の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

EDIT:
OS

  • のWindows 7 Professionalの64ビット版

  • としては、それらが私の設定やOSの詳細です要求

    ビジュアル・スタジオ:アップデートと2010アルティメット、2013コミュニティ、2015 Professionalの1つの

コンパイラの設定:Win32コンソールアプリケーションの

  • デフォルト設定、

  • デバッグのいずれかとリリース構成、

  • x86およびx64ターゲットプラットフォームarchit標準の実装*_forタイミング機能のためのsteady_clock使用すべきであると言っていますがectures

+0

早起きの場合は、一般的にループで 'sleep_until()'を使用します。私は早起きは起こるはずがないと思っていますが、GCC Linuxでは、プロセスがシグナルを受信するたびに早起きが起きているようです(明らかにあなたの問題ではありません)。 – Galik

+0

ローカルで同じ結果が表示されません。 http://rextester.com/l/cpp_online_compiler_visual(VS2015も使用しています)にあります。正確なコンパイラ設定、ターゲットアーキテクチャ、ホストOS、マシン仕様などに関する詳細情報を追加することを検討してください。 – Yirkha

+0

@ Yirkha:私の記述の条件について詳しく説明しました。あなたの結果については、私のシステムではほとんど違いがないように見えます。 – dawid

答えて

8

VS2015でsleep_for()メソッドの実装は、すでにSleep()システムコールの周りにループが含まれているので、任意のスプリアスウェイクアップは、それには影響しません - VC\crt\src\stl\cthread.c_Thrd_sleep()を参照してください。


あなたの問題の原因はおそらくという事実sleep_for()で、sleep_until()それが待機する時間を計算するchrono::system_clockを使用している、内部呼び出しますが、あなたはchrono::steady_clockを使用して時間を測定しています。

両方のタイマーの精度は同じですが、必ずしも同じ精度である必要はありません。その場合、system_clockが少し遅れていることがありますが、steady_clockはすでに数μs前ですが、system_clockを使用して計算された待機時間は実際に要求された時間よりも短くなります。この正確な場合


それは正確な時間測定に使用するのが好ましいのWindows APIだとして、それは、非常に正確かつ精密になりますので、steady_clockは、(VC\include\chronostruct steady_clockの検索を参照)QueryPerformanceCounter()を使用して実装されます。

system_clock

"精度の最も高い可能なレベル(< 1US)" もを約束している、(struct system_clockを検索し、VC\include\chrono参照)GetSystemTimePreciseAsFileTime()を用いて実現されます。悲しいかな、MSDNのページによれば、このAPIはWindows 8からのみサポートされており、Windows 7マシンで精度がmsの古いGetSystemTimeAsFileTime()に悩まされています。それはおそらく測定誤差の結果でしょう。


正確なユースケースに応じて、さまざまな方法でこれを処理できます。スレッドを中断し、スケジューラが目を覚ますのを待つことは、とにかく非常に正確ではないので、小さなエラーを無視することを検討したいと思います。

+0

'sleep_for 'と私の測定方法で使われているクロックの違いから、その理由が分かります。私は一時的に測定クロックを 'system_clock'に変更したことを確認するため、結果はまさに期待通りです。しかし、あなたがローカルでこの効果を再現していないので、かなり疑わしいです。あなたの 'sleep_for'が' steady_clock'を使うと思うようになります。もしそうなら、それがOSの条件に依存するなら、 'sleep_for'に' steady_clock'を使用する方法はありますか? – dawid

+0

これはCRTの内部で実装されており、 'chrono'インタフェースでも実装されていないため、再構築する必要があります。 Windows upgrade> = 8はすべてを解決するか、影響を受けるプラットフォームにわずかな時間を追加するだけです(「waitits for> = X」の要件を常にtrueにするため)。 – Yirkha

2

は、それが必要とされていません。また、非定常クロックを使用すると、クロックの調整によってスリープ時間が短くなる可能性があります。そのような場合、タイミング機能は、標準で指摘した有用な機能を提供しない可能性があります。

しかし、結果は一貫した短期間の落ち込みを示し、標準に準拠しない動作を示す可能性があります。

このような動作を回避するには、自分で選択した時計を使用して時間を測定し、目標時間が経過するまでループしてスリープします。

関連する問題