すべての BSD で使用可能であり、実際には POSIX 標準の一部として定義されているclock_gettime()関数を見ると、少なくとも 3 種類のクロックがサポートされていることがわかります (多くのシステムでは、これらのクロックよりも多くのクロックがサポートされています)。 、しかし実際には POSIX 標準では 1 つの存在のみが要求され、他のすべてはオプションです):
CLOCK_REALTIME - POSIX はこれが存在することを要求します。これが壁掛け時計です。
CLOCK_MONOTONIC - これが何なのか (そして SI 秒が何を意味するのか) はわかりませんが、この時計が逆方向にジャンプすることはなく、値が単調に増加することしかできないことは理解しています。
CLOCK_UPTIME - これが CLOCK_MONOTONIC とどのように異なるのかわかりません (アップタイムも後方にジャンプすることはありません) が、少なくともカーネルの起動時にこのクロックがゼロから始まることはわかっています (一方、カーネルの起動時に CLOCK_MONOTONIC が持つ初期値は定義されていません)。 )
他の時計はしばらく無視しましょう。CLOCK_REALTIME が単調にカウントアップすることは保証されていませんよね? これが実際の「システム時間」です。システム時刻を自由に変更できます。過去 3 か月または未来 5 年間に設定できますが、システムがネット上の NTP サーバーを使用して時刻を同期するたびに、時刻が前後する可能性があります。
現在、BSD システムには 2 つのスリープ関数があります。sleep()とnanosleep()。確かではありませんが、sleep() が nanosleep の上に実装されることを期待します。結局、nanosleep() を使用して sleep() を簡単にエミュレートし、構造体の timespec で秒数を設定するだけで、ナノ秒をゼロに保つことができます。 .
私は多くの情報源で、これらの関数が実際にウェイクアップ時間を計算することで機能し(現在の時間を取得し、それにスリープ時間を追加する)、現在の時間がウェイクアップよりも遅いかどうかをシステムが定期的にチェックすることを読みましたその場合は、スレッドを再び起動します。これが間隔を置いてのみチェックされるという事実が、現在のスリープが少なくともこの時間 (信号によって中断された場合のみ) スリープするが、それより長くスリープする可能性がある (頻度によっては) とマニュアルページに記載されている理由です。システムは、ウェイクアップ時刻をすでに過ぎているかどうかをチェックし、スケジューラがこのスレッドの再実行を許可するまでの時間に応じてチェックします)。
これは私にとって完全に正気です...しかし、常に私を悩ませていた質問が1つあります。
さまざまな情報源によると、スリープ (少なくとも nanosleep) は内部でクロックとして CLOCK_REALTIME を使用します。つまり、nanosleep() に 30 秒間スリープするように指示してから、システム クロックを将来の 1 時間に変更すると、スレッドはほぼ即座にウェイクアップします (将来の 1 時間は、ウェイクアップ時間 nanosleep( ) 計算)。これも全然オッケーです。しかし、私が 30 秒で目を覚ますと言った後、ユーザーが自分のシステム時計が 1 時間進んでいることに気づき、時計を 1 時間遅らせたらどうなるでしょうか? 次に、私のスレッドは 1 時間 30 秒間スリープしますか? それはかなり悪いでしょう。