【问题标题】:Difference between CLOCK_REALTIME and CLOCK_MONOTONIC?CLOCK_REALTIME 和 CLOCK_MONOTONIC 的区别?
【发布时间】:2011-04-01 04:59:22
【问题描述】:

您能解释一下clock_gettime() 在 Linux 上返回的 CLOCK_REALTIMECLOCK_MONOTONIC 时钟之间的区别吗?

如果我需要计算外部源生成的时间戳与当前时间之间的经过时间,哪个更好?

最后,如果我有一个 NTP 守护程序定期调整系统时间,这些调整如何与 CLOCK_REALTIMECLOCK_MONOTONIC 交互?

【问题讨论】:

    标签: linux


    【解决方案1】:

    CLOCK_REALTIME 代表机器对当前挂钟时间的最佳猜测。正如IgnacioMarkR 所说,这意味着CLOCK_REALTIME 可以随着系统时钟的变化(包括NTP)前后跳转。

    CLOCK_MONOTONIC 表示自过去某个任意固定点以来经过的绝对挂钟时间。它不受系统时钟变化的影响。

    如果您想计算在一台机器上观察到的两个事件之间的经过时间,而不需要重新启动,CLOCK_MONOTONIC 是最佳选择。

    请注意,在 Linux 上,CLOCK_MONOTONIC 不会测量挂起所花费的时间,尽管根据 POSIX 定义它应该这样做。您可以使用特定于 Linux 的 CLOCK_BOOTTIME 作为在挂起期间保持运行的单调时钟。

    【讨论】:

    • 请注意,在较新的内核上,CLOCK_MONOTONIC_RAW 是可用的,甚至更好(没有 NTP 调整)。
    • @JosephGarvin 对于“更好”的一些价值,也许 - CLOCK_MONOTONIC_RAW 可能会以百万分之几(或几百)的速度实时运行快或慢,并且它的速率可能会因环境条件而变化,例如温度或电压(或在虚拟机上窃取时间)。在正常工作的机器上,NTP 尽最大努力减轻所有这些因素,因此 CLOCK_MONOTONIC 更准确地反映了 true 已用时间。
    • 当然,有一个 CLOCK_MONOTONIC_PARBOILED 可能会很有趣,它受 NTP 纠正频率错误的努力影响,但不受其纠正相位错误的努力的影响,但对于可疑的增益来说,这很复杂: )
    • 我喜欢@hobbs 提出的观点。如果您担心程序会受到时钟漂移的影响怎么办?在这种情况下,CLOCK_MONOTONIC 会是最佳选择吗?例如Patriot Missile System
    • 我认为提到 CLOCK_REALTIME 受闰秒影响也很重要。这意味着每次插入闰秒时它产生双时间戳。上次发生这种情况是在 2012 年 6 月 30 日,当时有很多软件ran into trouble
    【解决方案2】:

    Robert Love 的书LINUX System Programming 2nd Edition,在第 11 章开头,第 363 页专门解决了您的问题:

    单调时间源的重要方面不是当前 值,但保证时间源是严格线性的 增加,因此对于计算时间差很有用 两次采样之间

    也就是说,我相信他假设这些进程在同一操作系统实例上运行,因此您可能希望运行定期校准以能够估计漂移。

    【讨论】:

      【解决方案3】:

      CLOCK_REALTIME受NTP影响,可以前后移动。 CLOCK_MONOTONIC 不是,并以每滴答一滴的速度前进。

      【讨论】:

      • CLOCK_MONOTONIC 受 NTP 时间调整(时间转换)的影响。但是它不会跳。
      • 但在较新的内核上有 CLOCK_MONOTONIC_RAW,它确实不受 NTP 影响。
      • "tick" -- 知道 Linux/amd64 上的一个刻度线有多大/多长/CPU 指令有多大?或者我可以在哪里获得有关这方面的文档?
      • @kevinarpe 不确定,但我认为滴答被定义为时间的一小部分,而不是 CPU 周期的数量,通常是 1/100 秒。
      • @Stéphane:我肯定必须小于 10 毫秒。我认为 Java 的 System.nanoTime() 使用 CLOCK_MONOTONIC 并且可以测量 1000ns 或更短的 durations。也许您正在考虑系统时间,有时会限制为毫秒?
      【解决方案4】:

      除了Ignacio's answerCLOCK_REALTIME 可以向前跳跃,偶尔向后跳跃。 CLOCK_MONOTONIC 两者都不做;它只是继续前进(尽管它可能会在重新启动时重置)。

      一个健壮的应用程序需要能够容忍CLOCK_REALTIME 偶尔向前跳跃(也许非常偶尔向后跳跃,尽管这更像是一种边缘情况)。

      想象一下当您暂停笔记本电脑时会发生什么 - CLOCK_REALTIME 会在恢复后向前跳,CLOCK_MONOTONIC 不会。在虚拟机上试一试。

      【讨论】:

      • 程序启动时CLOCK_MONOTONIC从0开始;它不适用于进程间使用。
      • @Benubird:程序启动时它不是从0开始的。那是CLOCK_PROCESS_CPUTIME_ID。快速测试:$ perl -w -MTime::HiRes=clock_gettime,CLOCK_MONOTONIC -E 'say clock_gettime(CLOCK_MONOTONIC)' --> 706724.117565279。这个数字与 Linux 上的系统正常运行时间相匹配,但标准说它是任意的。
      • 顺便说一句,我不相信CLOCK_MONOTONIC 在暂停/恢复时停止的 Linux 行为符合 POSIX。它应该是从过去某个固定点开始的时间,但是通过暂停/恢复停止时钟会破坏这一点。
      【解决方案5】:

      POSIX 7 引号

      POSIX 7 在http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html 处指定两者:

      CLOCK_REALTIME:

      此时钟代表系统测量实时的时钟。对于此时钟,由clock_gettime() 返回并由clock_settime() 指定的值表示自纪元以来的时间量(以秒和纳秒为单位)。

      CLOCK_MONOTONIC(可选功能):

      对于此时钟,clock_gettime() 返回的值表示自过去某个未指定时间点(例如,系统启动时间或纪元)以来的时间量(以秒和纳秒为单位)。该点在系统启动时间后不会改变。 CLOCK_MONOTONIC时钟的值不能通过clock_settime()设置。

      clock_settime() 给出了一个重要提示:POSIX 系统可以随它任意改变CLOCK_REALITME,所以不要依赖它既不连续也不向前流动。 NTP 可以使用clock_settime() 实现,并且只能影响CLOCK_REALTIME

      Linux 内核实现似乎将引导时间作为CLOCK_MONOTONIC 的纪元:Starting point for CLOCK_MONOTONIC

      【讨论】:

      • 这就是我真正想知道的!谢谢!
      【解决方案6】:

      抱歉,没有声誉将此添加为评论。所以它作为一个补充答案。

      根据您调用clock_gettime() 的频率,您应该记住只有一些的“时钟”是由Linux 在VDSO 中提供的(即不需要所有的系统调用)一个的开销——当 Linux 添加防御措施以防止类似 Spectre 的攻击时,这种情况只会变得更糟)。

      虽然 clock_gettime(CLOCK_MONOTONIC,...)clock_gettime(CLOCK_REALTIME,...)gettimeofday() 总是会非常快(由 VDSO 加速),但对于例如CLOCK_MONOTONIC_RAW 或任何其他 POSIX 时钟。

      这可能会随着内核版本和架构而改变。

      虽然大多数程序不需要注意这一点,但 VDSO 加速的时钟可能会出现延迟峰值:如果您在内核使用时钟计数器更新共享内存区域时正确地击中它们,它必须等待内核完成。

      这是“证明”(GitHub,让机器人远离 kernel.org): https://github.com/torvalds/linux/commit/2aae950b21e4bc789d1fc6668faf67e8748300b7

      【讨论】:

        【解决方案7】:

        CLOCK_REALTIME 和 MONOTONIC 之间有一个很大的区别。 CLOCK_REALTIME 可以根据 NTP 向前或向后跳跃。 默认情况下,NTP 允许时钟速率最多加快或减慢 0.05%,但 NTP 不能导致单调时钟向前或向后跳跃。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-01-24
          • 2012-12-25
          • 2012-06-10
          • 1970-01-01
          • 2012-12-24
          • 2013-01-21
          • 2017-03-23
          • 1970-01-01
          相关资源
          最近更新 更多