2017-08-08 2 views
1

通常、ある仕事をシミュレートするか、正確な時間間隔を待つ場合は、condition_variable::wait_forを使用するか、最悪の場合はthread::this_thread::sleep_forを使用します。しかし、condition_variabledocumentationは、wait_forまたはwait_untilメソッドが要求された時間より長くブロックする可能性があると述べています。 は、スケジューリングまたはリソースの競合の遅れに起因するtimeout_durationより長くブロックすることがあり正確なスレッドスリープ間隔を保証するにはどうすればいいですか?

この機能。

正確な待機間隔はどのように保証できますか?

UPDATE

私はcondition_variableずに到達することはできますか?

+4

標準C++には、このような機能はありません。そして、おそらくどちらもあなたのオペレーティングシステムはありません。 –

+0

おそらく最も近いことは、大きなインクリメント0.1秒以上でスリープして正しい戻り時間を待つ独自の関数を作ることですが、かなり面倒で非効率なものになります。 –

+0

@GradyPlayer:なぜですかあなたは任意の1秒を選んでいますか?より優先度の高いタスクを持つビジーなシステムでは、1000秒になることがあります。未使用のシステムでは、オーバーヘッドがゼロになる可能性があります。 – MSalters

答えて

6

これはできません。

このように正確な保証を得るためには、リアルタイムオペレーティングシステムが必要です。

C++は、あなたがリアルタイムオペレーティングシステムを使用していることを保証するものではありません。

したがって、RTOS以外の標準的な機能が保証されています。

この質問の範囲をはるかに超えるRTOSでのプログラミングには、他の複雑な問題があることに注意してください。

実際には、きめ細かなタイミング制御(フレーム単位やスキャンライン単位のバッファなど、オーディオバッファなど)が本当に必要なときには、時間は短く、もしそうならスピンウェイト。時間が長ければ、彼らは待つ時間よりも少し待ってから起きてスピンします。

これは動作するとは限りませんが、ほぼすべてのケースで十分に機能します。

RTOSでは、プラットフォームは必要に応じてプリミティブを提供します。これらは標準C++の範囲外です。私が知っている典型的なデスクトップOSはRTOSではありません。ファイタージェットのコントロールハードウェアなどをプログラミングする場合は、RTOSでプログラミングしている可能性があります。

私はあなたが戦闘機のジェット制御ソフトウェアを書いておらず、スタックオーバーフローについてこの質問をしていないことを願っています。

+0

誠実な答えは、最後の行が大好きです。 – Annabelle

+0

@ Yakk残念ながらさらに悪いことに。戦闘機のジェット制御ソフトウェアを書いている人は私に質問に答えるように頼んだ。 – Viktor

0

あなたが仮定した正確な持続時間の間正確に眠った後、応答として何らかのアクションを実行した場合(現在の時間の取得やメッセージのスクリーンへの印刷など)、未知の期間時間例プロセッサの負荷が原因です。これは(ほぼ)即座に起こるアクションに相当しますが、タイマーは予想以上に長くかかります。最適なケースのシナリオでも、タイマーが要求された時刻に正確に完了し、オペレーティングシステムが処理をプリエンプトせずに完了できるようにしても、そのアクションを実行するには数クロックサイクルかかるでしょう。

つまり、標準のオペレーティングシステムでは、タイマーが要求された時間に正確に完了することは不可能であるか、あるいは無意味でさえあります。

どのようにこれを克服できますか?学術的な答えは、リアルタイムオペレーティングシステムなどの特殊なソフトウェアやハードウェアを使用することができるということですが、通常のプログラミングよりもソフトウェアを開発する方がはるかに複雑です。おそらくあなたが本当に知りたいことは、一般的には、そのドキュメントが参照する遅延がそれほど大きくないことです。つまり、一般的に1/100秒未満です。例えばブルートフォースループ付き

0

...:あなたは、このような精度を持つことができないので、少し醜いです

chrono::microseconds sleep_duration{1000}; 

auto now = chrono::high_resolution_clock::now() 

while(true) 
{ 
    auto elapsed = chrono::duration_cast<hrono::microseconds>(chrono::high_resolution_clock::now() - now); 
    if (elapsed > sleep_duration) 
     break; 
} 

が、デスクトップオペレーティングシステムは、リアルタイムではありません。あなたが期待できるもの精度に依存

void little_sleep(std::chrono::microseconds us) 
{ 
    auto start = std::chrono::high_resolution_clock::now(); 
    auto end = start + us; 
    do { 
     std::this_thread::yield(); 
    } while (std::chrono::high_resolution_clock::now() < end); 
} 
+0

ありがとうございます。しかし、 'std :: chrono :: high_resolution_clock'は単なるエイリアスであることに注意してください。 [ここ](http://en.cppreference.com/w/cpp/chrono/high_resolution_clock)をチェックしてください。 – Viktor

+0

それは本当で、ubuntu 16.04では 'system_clock'のエイリアスです。クロックの精度が十分でない場合は、OS固有のコールを使用してください。 –

+0

これは正確なスリープを保証するものではありません。プリエンプティブOSはスレッドをいつでもスリープさせることができます(あなたのウェイトループを実行している間も)。だからあなたはそれを防ぐために何かをする必要があります(RTOSや協調スケジューラ(yieldなし)、スレッドのRT優先など)。) – geza

0

:あなたは、次のスニペットを見て、CPUを緩和するために

。一般的に言っているように、通常のOS(Linux、Windows)ではこれを保証することはできません。

なぜですか?
お使いのOSにはおそらくスレッドの概念があります。もしそうなら、スケジューラがスレッドを中断し、実行をキュー内で待機している他のスレッドに切り替える。そして、これはタイマーの精度を損なう可能性があります。

どうすればいいですか?

  1. あなたは組み込みシステムを使用している場合 - ベアメタルのために行く、すなわち OSを使用するか、いわゆるハードリアルタイムオペレーティングシステムを使用しないでください。
  2. Linuxを使用している場合は、GoogleのLinux RT Preempt Patchを探してください。カーネルを再コンパイルしてパスを組み込む必要があります(それほど複雑ではありません)。次に、カーネルのスレッドよりも優先順位が高い50以上の優先順位を持つスレッドを作成することができます。カーネルは一般的に、かなり良い時間精度を提供します。私の場合、3桁の大きさ(数msのレイテンシーから数えて私たちに)。
  3. Windowsを使用している場合は、このようなパッチについてはわかりませんが、MicrosoftサイトでHigh Precisionタイマーを検索できます。たぶん、提供された正確さは、あなたのニーズに十分です。
関連する問題