CLOCK_REALTIME和CLOCK_MONOTONIC之间的区别?


206

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

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

最后,如果我有一个NTP守护进程周期性地调整系统时间,怎么做这些调整与每个互动CLOCK_REALTIMECLOCK_MONOTONIC

Answers:


238

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

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

如果要计算在一台计算机上观察到的两个事件之间的经过时间,而又不进行中间重启,CLOCK_MONOTONIC则是最佳选择。

请注意,在Linux CLOCK_MONOTONIC上,虽然通过POSIX定义,它不会测量挂起所花费的时间。您可以将特定CLOCK_BOOTTIME于Linux 的单调时钟用于挂起期间保持运行。


11
请注意,在较新的内核上,可以使用CLOCK_MONOTONIC_RAW,它甚至更好(没有NTP调整)。
约瑟夫·加文2012年

14
@JosephGarvin代表“更好”的某个值,也许-CLOCK_MONOTONIC_RAW可能以百万分之几(或几百)的速度实时运行或慢速运行,其速度可能会因温度或电压(或偷窃时间)等环境条件而异。虚拟机)。在运行正常的计算机上,NTP会尽力减轻所有这些因素的影响,因此CLOCK_MONOTONIC更紧密地反映了真实的经过时间。
hobbs 2012年

23
的确,让CLOCK_MONOTONIC_PARBOILED受NTP纠正频率误差的影响而不受其纠正相位误差的影响可能是很有趣的,但这对于可疑的增益来说是非常复杂的:)
hobbs

1
我喜欢@hobbs提出的观点。如果您担心会受到时钟漂移影响的程序该怎么办?CLOCK_MONOTONIC在那种情况下会是最好的选择吗?例如,“ 爱国者”导弹系统
捷尔2014年

3
我认为提到CLOCK_REALTIME受leap秒影响也很重要。这意味着它加倍产生时间戳每一个闰秒被插入的时间。上一次是在2012年6月30日,很多软件都遇到了麻烦
user1202136 2014年

38

罗伯特·洛夫(Robert Love)的《LINUX系统编程第二版》一书在第11章第363页的开头专门解决了您的问题:

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

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


25

CLOCK_REALTIME受NTP影响,并且可以向前和向后移动。CLOCK_MONOTONIC不是,每跳一跳就跳一次。


15
CLOCK_MONOTONIC受NTP时间调整(时间转换)的影响。但是不会跳。
derobert

3
但是在更新的内核上有CLOCK_MONOTONIC_RAW,它实际上不受NTP的影响。
Joseph Garvin 2012年

1
“滴答”-在Linux / amd64上滴答有多大/长/ CPU指令的粗略概念?或者在哪里可以获取有关此文件的文档?
kevinarpe 2014年

@kevinarpe不确定,但我认为滴答定义为时间的一部分,而不是CPU周期的数量,通常是1/100秒。
斯特凡

@Stéphane:我肯定必须比10ms紧。我认为Java的System.nanoTime()用途CLOCK_MONOTONIC可以测量1000ns或更短的持续时间。也许您在考虑系统时间,有时会限制为毫秒?
kevinarpe

20

除了伊格纳西奥(Ignacio)的回答外CLOCK_REALTIME还可以飞跃向前,偶尔向后飞。CLOCK_MONOTONIC两者都不做;它只是继续前进(尽管它可能会在重新启动时重置)。

一个健壮的应用程序需要能够容忍CLOCK_REALTIME偶尔的向前跳跃(也许偶尔会非常轻微地向后跳跃,尽管这更多的是一种极端情况)。

想象一下,当您挂起笔记本电脑时会发生什么- CLOCK_REALTIME在履历表之后向前跳,CLOCK_MONOTONIC而不会。在虚拟机上尝试。


3
程序启动时,CLOCK_MONOTONIC从0开始;它不用于进程间使用。
Benubird

18
@Benubird:程序启动时它不会从0开始。那是CLOCK_PROCESS_CPUTIME_ID。快速测试:$ perl -w -MTime::HiRes=clock_gettime,CLOCK_MONOTONIC -E 'say clock_gettime(CLOCK_MONOTONIC)'-> 706724.117565279 该数字与Linux上的系统正常运行时间相匹配,但该标准表明它是任意的。
derobert

4
顺便说CLOCK_MONOTONIC一句,我不认为通过挂起/恢复停止的Linux行为符合POSIX。应该是从过去的某个固定时间开始的时间,但是在挂起/恢复上停止时钟会破坏该时间。
caf 2013年

15

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_settime()设置CLOCK_MONOTONIC时钟的值。

clock_settime()给出了一个重要提示:POSIX系统能够CLOCK_REALITME随其进行任意更改,因此不要依赖于它既不连续也不向前。NTP可以使用实现clock_settime(),并且只会影响CLOCK_REALITME

Linux内核实现似乎以启动时间为以下时间CLOCK_MONOTONICCLOCK_MONOTONIC的起点


0

抱歉,没有信誉将其添加为评论。因此,它是一个补充性答案。

根据您调用的频率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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.