yohhoyの日記

技術的メモをしていきたい日記

タイムアウト関数とsteady clock

C++11標準ライブラリの絶対時刻によるタイムアウト付き待機処理(xxx_until系関数)を常に意図通り動作させるには、クロックとしてstd::chrono::system_clockではなくstd::chrono::steady_clockを利用する*1

下記コードにおいてsystem_clock::is_steady == falseの場合、タイムアウト時刻に達するより前にシステム時刻調整が行われると、本来意図していたであろう「(A)時点の3分後にタイムアウト」とは異なる結果になる。

auto expires = std::chrono::system_clock::now() + std::chrono::minutes(3);  // (A)
//...
std::this_thread::sleep_until(expires);  // (B)

例えば(A)時点でのシステム時刻が 12:00 であった場合、(B)時点でのシステム時刻が 12:03 を超えるまでタイムアウト付き待機処理が行われる。(A)−(B)間にシステム時刻調整により -1:00(1時間時計を巻き戻す)された場合、結果として実時間で 1:03 の待機処理が行われる。詳細はN3337 30.2.4/p4を参照。

N3337 20.11.7.1/p1, 20.11.7.2/p1より一部引用。

1 Objects of class system_clock represent wall clock time from the system-wide realtime clock.

class system_clock {
public:
  static const bool is_steady = unspecified;
  //...
};

1 Objects of class steady_clock represent clocks for which values of time_point never decrease as physical time advances and for which values of time_point advance at a steady rate relative to real time. That is, the clock may not be adjusted.

class steady_clock {
public:
  static const bool is_steady = true;
  //...
};

関連URL

*1:C++11標準規格では、system_clock がsteady(=システム時刻調整の影響を受けない安定した時計)であるか否かを規定せず処理系に任せている。