CLOCK_REALTIME有什么用途?

11

我正在研究 CLOCK_REALTIMECLOCK_MONOTONIC 之间的区别。

CLOCK_REALTIME 和 CLOCK_MONOTONIC 的区别是什么?

CLOCK_REALTIME 在时间上存在不连续性,可能会向前或向后跳跃:这是时钟的一个错误吗?一个给出不一致时间的时钟怎么能可靠呢?


2
夏令时是墙上挂钟时间可能向前或向后跳动的一个例子。还要注意,答案明确指出,“这是系统的猜测”,当它确定先前的猜测错误时,会再次进行猜测。 - Jongware
3
@Bionix1441,这就是整个重点,每种时钟类型都有不同的用途,单调时钟适用于测量经过的时间(想一想 - 某事 花费了多长时间?),实时时钟作为时间指示器很有用(想一想 什么时候 发生了什么?)由于其设计方式,实时时钟不适合测量经过的时间(因为它可以前进和后退)。 - Nim
2
@RadLexus 夏令时不是可能使CLOCK_REALTIME向前或向后跳的示例。 - Steve Summit
1
@RadLexus:不,时钟的状态不考虑时区(包括夏令时);只有当它的状态被转换成人类可读的形式时,时区才可能被应用。时区是在此基础上的额外“层”,这就是为什么你在GUI上看到它“跳动”的原因。但是CLOCK_REALTIME本身并不会在时区更改(或夏令时的开始/结束)时跳动。 - Lightness Races in Orbit
3
听起来你现在明白了,但对于其他人想知道的人:人类可读时间会在夏令时切换时跳跃,但 CLOCK_REALTIME(例如它所基于的Unix/Posix时间)不会。CLOCK_REALTIME是UTC时间,没有时区或夏令时。它稍后被转换为人类可读时间,并在那里引入时区和夏令时偏移量。 - Steve Summit
显示剩余13条评论
1个回答

26

尽管存在不完美,CLOCK_REALTIME应该是系统对当前UTC或民用时间的最佳估计。它是系统显示与您手表、墙上的时钟、手机或收听广播电台的时间相同的基础。(显示确实涉及从UTC到本地时间的转换;稍后再讲解此问题。)

但是,如果CLOCK_REALTIME将与现实世界中的UTC时间匹配,至少存在两个相当重要的问题:

  1. 如果有人意外设置了您计算机上的时钟,怎么办?他们将不得不进行修复,而修复可能涉及时间跳跃。特别是如果错误很大(如几小时或几天),几乎没有办法避免。
  2. 大多数计算机不幸地无法表示闰秒。因此,当现实世界中出现闰秒时,大多数计算机时钟必须稍微调整一下。
当你阅读到CLOCK_REALTIME可能会有不连续性,可能会向前或向后跳跃时,这不是一个错误,而是一个特性:CLOCK_REALTIME必须具备这些可能性,以应对现实世界中的闰秒和偶尔出错的时钟。
因此,如果您正在编写的代码需要与现实世界中的时间匹配,无论它是否存在缺陷,CLOCK_REALTIME都是您想要的。但是,最好以这样的方式编写代码,即使系统时钟偶尔向前或向后跳跃,它也能表现得相当优雅(不会崩溃或做出奇怪的事情)。
正如您可能从参考的其他问题中了解到的那样,CLOCK_MONOTONIC保证每秒恰好向前步进一秒,没有跳跃或不连续性,但是时钟的绝对值并不重要。如果CLOCK_MONOTONIC的值为13:05,则并不意味着它刚刚在下午一点过一分,通常意味着计算机已经运行了13小时5分钟。
如果你只对相对时间感兴趣,那么CLOCK_MONOTONIC就足够了。特别是,如果你想计算某些操作的持续时间,从结束时间减去开始时间,最好使用CLOCK_MONOTONIC值,因为它们不会因为某种时间跳变(可能会影响CLOCK_REALTIME)而给出错误的答案。
简而言之,正如评论中所说,如果你需要绝对时间,就需要使用CLOCK_REALTIME,而如果你需要相对时间,使用CLOCK_MONOTONIC更好。
现在,再来说几点。

如前所述,CLOCK_REALTIME并不完全是“墙上时间”,因为它实际上处理的是UTC时间。它使用了著名(臭名昭著?)的Unix/Posix representation,表示自1970年以来的UTC秒数。例如,CLOCK_REALTIME值为1457852399,对应于2016年3月13日06:59:59 UTC时间。在我所在的地方,比格林威治西五个小时,这对应于当地时间01:59:59。但是一秒钟后,对我来说并不是凌晨2点!实际上,1457852399 + 1 = 1457852400对应于03:00:00东部时间,因为那时候夏令时在这里开始。

我曾经建议,如果你的时钟出错了,时间跳跃是修复它的唯一方法,但这并不完全正确。如果你的时钟只有轻微偏差,通过“缓慢调整”时间(略微改变时钟频率)是可以逐渐纠正它的,这样几分钟或几小时后,它就会漂移到正确的时间而无需跳跃。这就是NTP试图做到的,尽管根据其配置,它可能只愿意为相对较小的错误进行这样的操作。
我说CLOCK_MONOTONIC通常是计算机运行时间。但这并不被标准保证;所有标准都只是说CLOCK_MONOTONIC计算自某个任意时间点以来的时间。在将CLOCK_MONOTONIC实现为系统运行时间的系统上,有两种解释:它是自启动以来的时间,还是系统已经运行的时间(即减去任何睡眠或挂起的时间)?在许多系统上,还有另一个时钟CLOCK_BOOTTIME,它计算自启动以来的时间(无论是否处于开机或挂起状态),而CLOCK_MONOTONIC仅计算系统运行时间。
我说过,“CLOCK_MONOTONIC保证每秒恰好向前跳一秒”,但这可能也不完全正确。如果你的计算机正在进行时间调整操作,试图逐渐纠正绝对时间误差,那么实际情况可能是CLOCK_MONOTONIC暂时以1.001秒/秒、0.999秒/秒或类似的速度步进。差异通常会很小,但如果这对你很重要,一些系统还有其他类型的时钟可供使用,如CLOCK_MONOTONIC_RAW,据说没有这种扰动。

最后,如果您想要跟踪准确的时间,并且想要避免在闰秒时出现跳跃或间断,那么您会遇到问题,因为传统的Unix/Linux(以及Windows和其他所有)计算机系统对闰秒的处理非常不好。在最近的(4.x?)Linux内核下,有一个CLOCK_TAI可能会有所帮助。一些实验性系统可能会实现另一个时钟CLOCK_UTC,它可以正确处理带有闰秒的UTC时间。然而,这两种方法都有一些其他的成本,而且您必须真正知道自己在做什么才能有效地使用它们,至少在当前的支持水平下是如此。有关更多信息,请参见LEAPSECS邮件列表


4
非常出色的回答。以易于理解的方式涵盖了所有要点。 - Lightness Races in Orbit
这就是NTP试图做的事情,尽管结果是它只愿意为那些相当小的错误(比如不到一秒钟)进行校正。这完全可以在你的NTP客户端进行配置。 - Lightness Races in Orbit
@LightnessRacesinOrbit 但我认为其他ntp实现不那么挑剔,所以我调整了措辞。 - Steve Summit
1
@SteveSummit 很棒的回答。谢谢。 - Bionix1441
就我所知,我不相信将CLOCK_MONOTONIC解释为“系统已经运行的时间”符合POSIX标准:自过去某一时刻以来的时间并不会因为系统休眠而停止计算。 - caf
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接