在我测试的两个系统(32位Ubuntu 12.04服务器和64位Ubuntu 13.10 VM)上,time()给出的纪元以来的秒数可能与{{3}不同}' S
具体来说,虽然在调用time()
后我致电gettimeofday()
,但time()
返回的值有时小于 { {1}}返回{1}}值。
这显然发生在时钟滚动到新的一秒之后。
这导致我的一些代码中的错误导致时间()和gettimeofday()的秒数可以互换。
演示此问题的示例代码:
tv_sec
请注意,我调用time()次,只会抱怨其值 less 而不是gettimeofday()&#39>。
示例输出:
gettimeofday()
即,两个值相同的是3300万次,它们相差177k次,并且它们在新的秒的5844微秒内总是不同。
这是一个已知问题吗?是什么原因造成的?
答案 0 :(得分:18)
两个调用都是作为内核系统调用实现的。这两个函数最终都读取struct timekeeper
,两者都指向同一个实例。但是他们用它做了什么不同:
使用get_seconds()
函数,这是此的快捷方式:
struct timekeeper *tk = &timekeeper;
return tk->xtime_sec;
它只返回xktime_sec
。
gettimeofday()
gettimeofday()
使用do_gettimeofday()
(通过getnstimeofday
),其中同时读取字段xktime_sec
和xktime_nsec
(通过timekeeping_get_ns
)。在这里可能会发生xktime_nsec
比一秒更多纳秒。这个潜在的额外时间用于通过调用执行此操作的函数tv_sec
来增加timespec_add_ns()
字段:
a->tv_sec += __iter_div_u64_rem(a->tv_nsec + ns, NSEC_PER_SEC, &ns);
a->tv_nsec = ns;
因此,tv_sec
可能比xktime_sec
字段大。而且你有它:time()
给你的东西和gettimeofday()
给你的东西有点不同。
我今天在fluxbox反对这个问题,直到找到一个更好的解决方案,我就是这样:
uint64_t t_usec = gettimeofday_in_usecs(); // calcs usecs since epoch
time_t t = static_cast<time_t>(t_usec / 1000000L);
答案 1 :(得分:9)
time
和gettimeofday
都实现为所谓的Linux vsyscalls。意味着您的代码将被重定向到内核拥有,但是包含仅定期更新的结果的用户空间映射页面。
在Ubuntu中(我没有在RedHat Linux中观察到这种行为)gettimeofday
的值在time
的值之前更新,因此可能会得到不一致的值:
内核更新
gettimeofday
您查询
gettimeofday
您查询
time
内核更新
time
交换你的电话会产生一致的结果:
t = time(NULL);
gettimeofday(&tv, NULL);
if (t > tv.tv_sec) { ...
答案 2 :(得分:3)
这种行为是由于在Linux内核中实现了计时。
Linux维护一个跟踪当前挂钟时间的变量;这保持为纳秒级精度并定期更新。 (在最近的内核版本中它是tk_core.timekeeper.{xtime_secs, tkr_mono.xtime_nsec}
。)
time()
调用get_seconds()只返回此变量的秒部分 - 因此,根据挂钟时间的更新时间,可能会返回稍微过时的值。
gettimeofday()
不仅读取挂钟变量的最新值,而且(通过timekeeping_get_ns())从硬件时钟(通常是x86系统中的TSC读取新值,虽然这可以在运行时配置)并应用更正。
由于这种更正计算,gettimeofday()
返回的结果可能会翻到下一秒,因此返回的tv_sec
值高于time()
的结果