時間 API は異なる問いに答えます。市民時刻はある時点を示し、単調時刻は区間を測定し、CPU クロックは処理が消費した実行時間を測定します。 誤ったクロックを選ぶと、タイムアウトが実時間の補正に反応したり、I/O 待ち時間が測定から消えたりします。
クロックの選択 #
clock_gettime は clockid_t を struct timespec に読み込みます。その tv_sec と tv_nsec フィールドは秒とナノ秒を表します。
POSIX は、エポックから測定するシステム市民時刻 CLOCK_REALTIME と、起点が未規定で設定できない CLOCK_MONOTONIC を要求します。
タイムスタンプには実時間を、経過時間と期限には単調時刻を使います。
対応している場合、CLOCK_PROCESS_CPUTIME_ID と CLOCK_THREAD_CPUTIME_ID はプロセスまたは 1 スレッドが消費した CPU 実行時間を測定します。
I/O でブロックされた時間やスケジュールから外れていた時間は含みません。Linux にはサスペンド時間を含む CLOCK_BOOTTIME もありますが、
これは移植可能な POSIX の選択肢ではなく Linux 拡張です。
struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);
/* operation */
clock_gettime(CLOCK_MONOTONIC, &end);clock_getres は実装の分解能を報告しますが、連続した読み取り値が異なることを保証するものではありません。
スケジューリング遅延、タイマーの集約、ハードウェアがコードの実行時点に影響します。
時点が time_t に収まらない場合、呼び出しは EOVERFLOW で失敗することがあります。
tv_nsec を検証し、秒境界をまたぐ算術を正規化し、time_t の幅が固定だと仮定しないでください。
スリープとタイマー #
nanosleep は相対的な遅延を指定します。シグナルによって EINTR で中断され、残り時間が報告されることがありますが、
その残り時間から再開しても、周期処理では処理時間とスケジューリング遅延が蓄積します。
各周期に 1 つの絶対的な単調時刻の期限を計算し、clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, ...) で待機します。
期限を過ぎていれば直ちに戻るため、呼び出し側は処理をスキップするか追いつくかを選択する必要があります。
POSIX タイマーは timer_create と timer_settime を使います。TIMER_ABSTIME によって要求した満了時刻は、
タイマーが選択したクロック上の絶対時刻になります。通知にはシグナルまたはスレッド通知を使え、それぞれキューイングとライフタイムへの影響が異なります。
Linux の timerfd_create は POSIX ではありませんが、タイマー満了を poll、select、epoll と統合します。
alarm と setitimer は旧来のシグナル指向インターフェースです。
相対待機は後の CLOCK_REALTIME 調整の影響を受けませんが、絶対的な実時間の期限はそのクロックとともに移動します。
したがって、製品要件が明示的に「この市民時刻の瞬間に」でない限り、タイムアウトの期限は単調クロックで表現します。
市民時刻とタイムゾーン #
time_t はスカラーの時刻値であり、struct tm は分解された暦時刻です。gmtime_r は UTC に変換し、
localtime_r はプロセスのタイムゾーン規則を使って変換します。_r のない対応関数は再利用可能な静的領域を使います。
mktime は struct tm をローカル市民時刻として解釈し、tm_isdst を -1 に設定すると夏時間の状態を判定します。
timegm は分解された UTC の解釈に便利な GNU 拡張ですが、POSIX インターフェースではありません。
TZ と tzset はプロセスのタイムゾーン状態を制御します。秋の夏時間移行中のローカル時刻は 2 つの時点を示す場合があり、
春にスキップされたローカル時刻はどの時点も示さない場合があります。時点は UTC または time_t として保存し、
人間向けの値で市民時刻としての意味を保持する必要がある場合は、明示的なゾーンまたはオフセットを持たせます。
POSIX 時刻はうるう秒を独立したスカラー時刻の秒としてモデル化しません。システムは同期時に実時間クロックをステップ調整またはスミアする場合があります。
したがって、time_t の算術だけでも UTC 変換 API だけでも、うるう秒を完全には表現できません。
POSIX クロック仕様 と
clock_nanosleep(3) には、移植可能な詳細と Linux 固有の詳細が定義されています。
コメント
GitHub で閲覧・コメントする(投稿にはログインが必要です)