Cコードのtimespec_get()の秒コンポーネントの1秒遅れてtime()が報告する時間がなぜですか?


12

次のコードスニペット:

struct timespec ts;
for (int x = 0; x < 100000000; x++) {
    timespec_get(&ts, TIME_UTC);
    long cTime = (long) time(NULL);
    if (cTime != ts.tv_sec && ts.tv_nsec < 3000000) {
        printf("cTime: %ld\n", cTime);
        printf("ts.tv_sec: %ld\n", ts.tv_sec);
        printf("ts.tv_nsec: %ld\n", ts.tv_nsec);
    }
}

この出力を生成します:

...
cTime: 1579268059
ts.tv_sec: 1579268060
ts.tv_nsec: 2527419
cTime: 1579268059
ts.tv_sec: 1579268060
ts.tv_nsec: 2534036
cTime: 1579268059
ts.tv_sec: 1579268060
ts.tv_nsec: 2540359
cTime: 1579268059
ts.tv_sec: 1579268060
ts.tv_nsec: 2547039
...

なぜ間の矛盾cTimets.tv_sec?条件をに変更しても問題は発生しないことに注意してくださいts.tv_nsec >= 3000000。この問題は、ナノ秒が3000000よりも小さいことに依存しています。


使用するオペレーティングシステム、そのバージョン、使用するCライブラリのバージョンについて、より具体的にする必要があります。
プログラマー

2
@Someprogrammerdude Linux Debian 8、GCC 6.3.0。
テオドール

なにtimespec_get()?これはCまたはC ++ですか?のように見えstd::timespec_getます。適切なタグを使用してください。
Marco Bonelli

@MarcoBonelli:C11でCに追加されました。オンラインで再現できます
ShadowRanger

@ShadowRangerは参考にしていただきありがとうございます。システムのmanエントリが見つからなかったtimespec_getため、結論にジャンプしました。理にかなっています。
Marco Bonelli

回答:


11

その理由は、(暗黙的に)異なるシステムクロックを使用しているためです。timespec_get()使用する高解像度ながら、システム全体のリアルタイムクロックをtime()使用粗いリアルタイムクロック。

使ってみる

clock_gettime(CLOCK_REALTIME_COARSE, &ts);

の代わりにtimespec_get()、違いはなくなります。

編集:

これは、Linuxカーネルソース、vclock_gettime.cで確認できます。

確かに問題はここで見るには少し微妙です。によって使用されCLOCK_REALTIME_COARSECLOCK_REALTIME同じ値を含む構造体メンバーの秒部分は、ナノ秒部分が異なります。(1秒です)CLOCK_REALTIMEより大きくすることができます1000000000。この場合、それは呼び出しで修正されます:

ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
ts->tv_nsec = ns;

この修正はCLOCK_REALTIME_COARSE、でもでも実行されませんtime()。これは、違いを説明CLOCK_REALTIMEしてをtime()


これはどこかに文書化されていますか、それともtime(おそらく)パフォーマンスは高いが精度が低いクロックで実装されたアーティファクトですか(とにかく2番目の粒度しか持たないため、誰が精度を必要とするのでしょうか)。2番目の粒度を要求するだけの場合、リアルタイムで1ミリ秒ほど遅れる(オンラインテストでは、時々msを超える遅れが見られますが、それほど遅れることはありません)と私が思うにそれほど重要ではありません。
ShadowRanger

@ShadowRanger詳細を追加しました
Ctx

意図の明確な文書化ではありませんが、賛成投票にはこれで十分です。:-)時計が実際には1秒以上の追加のナノ秒を報告できるのはおかしい。
ShadowRanger

@ShadowRangerそのソース以外の実際のドキュメントを見つけることができませんでした。つまり、動作も事前の通知なしに詳細に変更される可能性があります
Ctx

@Ctx詳しい回答ありがとうございます!timespec_get()はPOSIXではなくC11であり、どのクロックを使用するかを設定する必要がないため、私はあなたが助言するclock_gettime()ではなくtimespec_get()を使用します。別の時計が使用されているとは思いもしませんでしたが、選択肢があれば、粗い時計を使用することにあまり意味がありません。
テオドール
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.