time()和gettimeofday()返回不同的秒数

时间:2014-04-07 15:56:44

标签: c linux time gettimeofday

在我测试的两个系统(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微秒内总是不同。

这是一个已知问题吗?是什么原因造成的?

3 个答案:

答案 0 :(得分:18)

两个调用都是作为内核系统调用实现的。这两个函数最终都读取struct timekeeper,两者都指向同一个实例。但是他们用它做了什么不同:

time()

使用get_seconds()函数,这是此的快捷方式:

struct timekeeper *tk = &timekeeper;
return tk->xtime_sec;

它只返回xktime_sec

gettimeofday()

另一方面,

gettimeofday()使用do_gettimeofday()(通过getnstimeofday),其中同时读取字段xktime_secxktime_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)

timegettimeofday都实现为所谓的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()的结果