24

C++11 では、*_untilタイムアウト関数は、安定したクロック (つまり、不変の速度でのみ前進するクロック) が使用されている場合にのみ、「期待どおり」に動作します。system_clockは安定したクロックではないため、次のようなコードは非常に驚くべき動作をする可能性があります。

using namespace std::chrono;
std::this_thread::sleep_until(system_clock::now() + seconds(10));

これにより、現在のスレッドは、スリープ期間中 (夏時間など) にシステム クロックが調整されない限り、10 秒間スリープ状態になります。スリープ中にクロックを 1 時間戻すと、現在のスレッドは 1 時間 10 秒間スリープします。

私が知る限り*_until、C++11 のすべてのタイムアウト関数には、タイム*_forポイントではなく期間を取る対応する関数があります。たとえば、上記のコードは次のように書き換えることができます。

using namespace std::chrono;
std::this_thread::sleep_for(seconds(10));

関数は、*_for関数の実行中に調整されるクロックについて心配する必要はありません。待機が終了したときの時間ではなく、待機時間を指定するだけだからです。

Future および try_lock 関数でのタイムアウトベースの待機についても同様であるため、この問題はスリープ関数以外にも影響します。

*_until不安定なクロックで機能を使用することが理にかなっていると想像できる唯一の状況は、クロックの調整を考慮したい場合です現在とその後の間のサマータイムへ、またはサマータイムから。*_until関数が関数よりも意味を持つ他の状況はあり*_forますか? *_forそうでない場合、一般的に、タイムアウト関数は関数よりも優先されるべきであると言っても過言ではありません*_untilか?

4

3 に答える 3

9

xxx_untilの呼び出しは、締め切りがあるときのためのものです。典型的なユース ケースは、複数の待機を含むコード セクションの厳しい時間制限がある場合、または待機前の各ステップで消費される時間が予測できない場合です。

例えば

void foo() {
  std::chrono::steady_clock::time_point const timeout=
    std::chrono::steady_clock::now()+std::chrono::milliseconds(30);

  do_something_which_takes_some_time();

  if(some_future.wait_until(timeout)==std::future_status::ready)
    do_something_with(some_future.get());
}

some_futureこれは、 からの時間を含めて、開始から 30 ミリ秒以内に準備ができている場合にのみ、 からの値を処理しますdo_something_which_takes_some_time()

この例のように、xxx_until関数のほとんどの使用例では、タイムアウトを予測できるようにするために安定したクロックを使用します。

固定されていないクロック ( など) でxxx関数を使用することを想像できる唯一のケースは、タイムアウトがユーザーに表示され、選択したクロックの値に依存する場合です。目覚まし時計やリマインダー プログラムはその一例であり、「真夜中に」実行されるバックアップ プログラムは別の例です。_untilstd::chrono::system_clock

于 2012-06-26T08:39:06.527 に答える
4

この関数のユースケースの1つsleep_untilは、特定の期間ではなく、特定の時間までスリープしたい場合です。

たとえば、毎日午後3時にのみアクティブ化する必要があるスレッドがある場合は、で使用する期間(夏時間とうるう年の処理を含む)を計算するか、を使用sleep_forできますsleep_until

于 2012-06-26T05:10:12.313 に答える
3

の良い使い方の 1 つsleep_untilは、定常時間ループ (ゲーム ループなど) です。サイクルの処理にかかる時間が不明であるが、通常は特定の最小限の長さでなければならない場合は、time_point をインクリメントして、サイクル期間までスリープさせることができます。例えば:

// requires C++14
#include <iostream>
#include <thread>
#include <chrono>

using namespace std;
using namespace std::chrono;
using namespace std::literals;

int main()
{
  auto start_time = steady_clock::now();

  for (auto i = start_time; i <= start_time + 1s; i += 50ms) {
    this_thread::sleep_until(i);
    cout << "processing cycle..." << endl;
  }

  return 0;
}

ただし、サイクルがインクリメント時間よりも長くかかる場合は、おそらくラグを追跡する必要があります。

アイデアは、素朴に 、サイクル期間ループ内コードの実行にかかる時間をsleep_forスリープ状態にすることです。

于 2014-05-24T10:43:52.000 に答える