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

Jos*_*ley 21 c linux time gettimeofday

在我测试的两个系统上(一个32位的Ubuntu 12.04服务器和一个64位的Ubuntu 13.10 VM),time()给出的纪元以来的秒数可能与gettimeofday()不同.

具体来说,虽然我在调用time() 调用gettimeofday(),但返回的值time()有时小于tv_sec返回的值gettimeofday().

这显然发生在时钟滚动到新的秒钟之后.

这导致了我的一些代码中的错误,这些代码期望time()和gettimeofday()的秒可以互换.

示例代码演示此问题:

#include <stdio.h>
#include <time.h>
#include <sys/time.h>

int main()
{
  time_t start = time(NULL);
  int same = 0;
  int different = 0;
  int max_usec = 0;
  while (1) {
    time_t t;
    struct timeval tv;
    gettimeofday(&tv, NULL);
    t = time(NULL);
    if (t < tv.tv_sec) {
      different++;
      if (tv.tv_usec > max_usec) {
        max_usec = tv.tv_usec;
      }
    } else {
      same++;
    }
    if (t > start + 5) {
      break;
    }
  }
  printf("Same:      %i\n", same);
  printf("Different: %i\n", different);
  printf("Largest difference seen at %i\n", max_usec);
}
Run Code Online (Sandbox Code Playgroud)

请注意,我调用time()第二个,只是抱怨它的值小于 gettimeofday()的值.

样本输出:

Same:      33282836
Different: 177076
Largest difference seen at 5844
Run Code Online (Sandbox Code Playgroud)

即,两个值相同的是3300万次,它们相差177k次,并且它们在新的秒的5844微秒内始终不同.

这是一个已知的问题?是什么导致这个?

aki*_*ira 21

这两个调用都是作为内核系统调用实现的.两个函数最终都读取a struct timekeeper,两者都指向同一个实例.但他们在做什么方面有所不同:

时间():

使用get_seconds()函数,这是一个快捷方式:

struct timekeeper *tk = &timekeeper;
return tk->xtime_sec;
Run Code Online (Sandbox Code Playgroud)

它只是回来了xktime_sec.

gettimeofday():

gettimeofday()另一方面,使用do_gettimeofday()(via getnstimeofday)读取字段xktime_sec以及xktime_nsec(via 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;
Run Code Online (Sandbox Code Playgroud)

所以,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);
Run Code Online (Sandbox Code Playgroud)


Ser*_* L. 9

双方timegettimeofday实现为所谓的Linux vsyscalls.意味着您的代码将被重定向到内核所拥有的,但是包含仅定期更新的结果的用户空间映射页面.

在Ubuntu中(我没有在RedHat Linux中观察到这种行为),值的值gettimeofday在值之前更新,time因此可能会得到不一致的值:

内核更新 gettimeofday

你查询 gettimeofday

你查询 time

内核更新 time

交换你的电话会产生一致的结果:

t = time(NULL);
gettimeofday(&tv, NULL);
if (t > tv.tv_sec) { ...
Run Code Online (Sandbox Code Playgroud)

  • 顺序无关紧要,请参阅我的答案。这两个函数也使用相同的时间结构作为基,同时为这两个函数更新(因为它是同一个实例)。差异是累积纳秒的数量,以及是否将它们添加到返回的秒数中。 (2认同)

ric*_*vdh 7

这种行为是由于在 Linux 内核中实现了计时。

Linux 维护一个跟踪当前挂钟时间的变量;这保持在纳秒精度并定期更新。(它是tk_core.timekeeper.{xtime_secs, tkr_mono.xtime_nsec}在最近的内核版本中。)

time()调用get_seconds()它只返回此变量的秒部分 - 因此,根据挂钟时间更新的时间,可能会返回一个稍微过时的值。

gettimeofday()不仅读取挂钟变量的最新值,而且(通过timekeeping_get_ns())从硬件时钟(通常是x86 系统中的TSC,尽管这可以在运行时配置)进行新的读取并应用更正。

由于该校正计算, 返回的结果有可能gettimeofday()滚动到下一秒,因此返回tv_sec比 的结果更高的值time()