调用 clock_gettime() 时,返回的 tv_nsec 字段实际上可能超过一秒吗?

When invoking clock_gettime() may the returned tv_nsec field actually exceed a second?

当您调用 clock_gettime() 时,它 returns 一个 timespec 结构。

struct timespec {
    time_t tv_sec; /* seconds */
    long tv_nsec; /* nanoseconds */
};

我在手册页中找不到 tv_nsec 不会超过一秒的保证。担保是否真实存在?它可能依赖于 linux 的库 (glibc?) 实现吗?

关键思想是:我是否需要 'normalize' 来自 clock_gettime() 函数的任何结果?

我相当确定答案总是"no"。

clock_gettime 不会 return 且 tv_nsec >= 10e9。 clock_settime() 和 clock_nanosleep() 都对他们的输入施加了这个限制,所以我一直认为 clock_gettime 与此一致。

同样在 Linux + glibc 上,如果你足够深入地研究 glibc,你会看到这样的代码:

摘自glibc/nptl/pthread_clock_gettime.c:

/* Compute the seconds.  */
tp->tv_sec = tsc / freq;

/* And the nanoseconds.  This computation should be stable until
   we get machines with about 16GHz frequency.  */
tp->tv_nsec = ((tsc % freq) * 1000000000ull) / freq;

这也发生在 glibc/sysdeps/unix/clock_gettime.c.

但是你是对的,手册页没有说。至少我的 Linux 发行版或 opengroup.org 上没有。因此,实施在技术上可能会发生变化 w/o 警告。

如果您正在为 Linux + glibc 写作,我会说您很安全。您可以自己检查备用开源 libc 库,例如Android 的仿生,或按比例缩小的 newlib。

如果您的目标是其他闭源 POSIX 系统,您或您的客户在支付支持费用方面存在问题,因此如果没有记录,请询问供应商。

如果试图尽可能便携并且感觉偏执,请用这样的 "normalizing" 函数包装 clock_gettime:

int my_gettime( struct timespec * ts ) 
{  
   int ret; 
   if( 0 == (ret = clock_gettime(SOME_CLOCK, ts))
   {
      while (tv_nsec >= 1000000000 )
      {
         ts->tv_nsec -= 1000000000;
         ts->tv_sec += 1;
      }
   }
   return ret;
}

不,您不需要对结果进行标准化。您可以相信纳秒字段在 0 到 999999999 之间(含)。

clock_gettime() 的 POSIX 规范明确指出,如果 tv_nsec < 0 || tv_nsec >= 1000000000.

clock_settime() 将失败并显示 EINVAL

标准的学究们可能会争辩,但简单的对称本身就告诉我们,我们可以期待 clock_gettime() 的结果相同。从技术上讲,10e9 ns 是一秒,并且由于标准始终使用术语 "seconds and nanoseconds",因此合乎逻辑的结论是纳秒字段应该被归一化。此外,如果 clock_gettime() 要 return 结果纳秒字段超出范围,许多程序将以有趣和迷人的方式出现故障。

根据opengroup

The tv_nsec member is only valid if greater than or equal to zero, and less than the number of nanoseconds in a second (1000 million). The time interval described by this structure is (tv_sec * 10'-.4m'9'.4m' + tv_nsec) nanoseconds.

所以按照opengroup的说法,官方说肯定是1秒以内。