clockid_t (clock_gettime 第一个参数) 可移植性

Posted

技术标签:

【中文标题】clockid_t (clock_gettime 第一个参数) 可移植性【英文标题】:clockid_t (clock_gettime first argument) portability 【发布时间】:2015-09-13 10:50:15 【问题描述】:

大多数 POSIX 兼容系统都提供了获取或设置高分辨率计时器的功能:

int clock_gettime(clockid_t clock_id, struct timespec *tp);

每个系统的文档通常列出几个符号名称作为可能的clock_id 值,但从未提及实际数值。事实证明,不仅不同系统的数值不同,而且相同含义的符号名称也不相同。更重要的是,并非系统实际支持的所有时钟都在 time.h (bits/time.h) 中定义 — 有些只定义在,比方说, linux/time.h.


也就是说,在Linux系统中我们可能有:

#define CLOCK_REALTIME                  0
#define CLOCK_MONOTONIC                 1
#define CLOCK_PROCESS_CPUTIME_ID        2
#define CLOCK_THREAD_CPUTIME_ID         3
#define CLOCK_MONOTONIC_RAW             4
#define CLOCK_REALTIME_COARSE           5
#define CLOCK_MONOTONIC_COARSE          6
#define CLOCK_BOOTTIME                  7
#define CLOCK_REALTIME_ALARM            8
#define CLOCK_BOOTTIME_ALARM            9
#define CLOCK_SGI_CYCLE                10      // In linux/time.h only.
#define CLOCK_TAI                      11      // In linux/time.h only.

在 Cygwin 环境中(不是逐字摘录):

#define CLOCK_REALTIME                  1       // Means CLOCK_MONOTONIC?
#define CLOCK_MONOTONIC                 4       // Means CLOCK_MONOTONIC_RAW?
#define CLOCK_PROCESS_CPUTIME_ID        2
#define CLOCK_THREAD_CPUTIME_ID         3

在 FreeBSD 中:

#define CLOCK_REALTIME                  0
#define CLOCK_VIRTUAL                   1
#define CLOCK_PROF                      2
#define CLOCK_MONOTONIC                 4
#define CLOCK_UPTIME                    5       // Synonymous to CLOCK_BOOTTIME?
#define CLOCK_UPTIME_PRECISE            7
#define CLOCK_UPTIME_FAST               8
#define CLOCK_REALTIME_PRECISE          9       // Same as CLOCK_REALTIME?
#define CLOCK_REALTIME_FAST            10       // Synonymous to CLOCK_REALTIME_COARSE?
#define CLOCK_MONOTONIC_PRECISE        11       // Same as CLOCK_MONOTONIC?
#define CLOCK_MONOTONIC_FAST           12       // Synonymous to CLOCK_MONOTONIC_COARSE?
#define CLOCK_SECOND                   13
#define CLOCK_THREAD_CPUTIME_ID        14
#define CLOCK_PROCESS_CPUTIME_ID       15

在 AIX 中:

#define CLOCK_REALTIME                ...
#define CLOCK_MONOTONIC               ...
#define CLOCK_PROCESS_CPUTIME_ID      ...
#define CLOCK_THREAD_CPUTIME_ID       ...

在 SunOS 中:

#define CLOCK_REALTIME                ...
#define CLOCK_HIGHRES                 ...       // Synonymous to CLOCK_MONOTONIC_RAW?

在 QNX 中:

#define CLOCK_REALTIME                ...
#define CLOCK_SOFTTIME                ...
#define CLOCK_MONOTONIC               ...

等等。


这让我想知道如何以可移植的方式将clock_gettime()CLOCK_REALTIME 以外的第一个参数一起使用。例如,如果我想使用CLOCK_MONOTONIC_COARSECLOCK_BOOTTIME,我怎么知道BSD 分别称它们为CLOCK_MONOTONIC_FASTCLOCK_UPTIME

根据前 4 个符号名称的数值做出假设是否明智?如:

#define POSIX_CLOCK_REALTIME            0
#define POSIX_CLOCK_MONOTONIC           1
#define POSIX_CLOCK_PROCESS_CPUTIME_ID  2
#define POSIX_CLOCK_THREAD_CPUTIME_ID   3
#define POSIX_CLOCK_MONOTONIC_RAW       4

#if CLOCK_REALTIME == POSIX_CLOCK_MONOTONIC
    #warning This platform has monotonic realtime clock.
#end if
#if CLOCK_MONOTONIC == POSIX_CLOCK_MONOTONIC_RAW
    #warning This platform has undisciplined monotonic clock.
#end if

如果一个系统实际上支持CLOCK_TAI,但没有在time.h中定义它,我该如何检查和使用它,考虑到相同的数值11可能代表@987654337 @ 或其他系统中的任何内容?

【问题讨论】:

不,做假设是不安全的。首先,您需要研究目标系统上的每个时钟,看看哪些时钟与另一个时钟匹配。那么您可能应该使用条件编译(例如#ifdef __linux__)为您的应用程序选择正确的时钟。 @JoachimPileborg 在看到所有这些差异之后,我现在担心即使是 #ifdef __linux__ 方法对于所有具有不同程度的定制和私有扩展的基于 Linux 的系统(由那些我的意思是经过大量修改的系统,而不仅仅是重新命名和重新设计的发行版)。 如果系统没有在time.h中定义CLOCK_TAI,你怎么知道它是否真的支持? @SteveSummit 运行时检查是可能的,因为clock_gettime 如果时钟受支持且当前可用(具有有效值)返回零,否则返回非零。如果所有系统的数值都相同,那么定义自己的常量就足够了,不依赖于系统提供的包含文件(往往会不同步)并避免命名不一致。但是,不幸的是,数值是模棱两可的。 【参考方案1】:

如果我试图编写一个最大可移植性的程序,我会限制自己使用相关标准中定义的符号值。 (根据你的说法,这听起来像 CLOCK_REALTIME——也许只有那个值——是标准的。)

如果某些系统实现了我想使用的有用扩展,我会通过以下方式测试它们

#ifdef CLOCK_MONOTONIC_COARSE
... my code calling clock_gettime(CLOCK_MONOTONIC_COARSE, &ts) ...
#endif

如果确实存在一些系统,其中相同的符号值最终意味着截然不同的事物,我会举起双手并宣布这是可移植性的噩梦,至少我尝试过的那种远离。

在回答您的其他问题时,(1) 不,对符号值进行假设是不明智的,(2) 没有好的方法可以使用确实存在但未在 time.h 中定义的时钟(尽管这种情况希望很少见)。

另外,您是否假设仅仅因为数值 1 在 Linux 上用于 CLOCK_MONOTONIC 而在 Cygwin 下用于 CLOCK_REALTIME 意味着这些时钟可能以某种方式相同?情况可能并非如此。这些数字是任意的,你不应该关心它们;这就是符号常量存在的原因!

【讨论】:

“符号值最终是否意味着截然不同的事物”是一个单独的问题;我天真地希望行为差异应该是最小的。相反,我谈论的是相反的问题——不同的系统对于相同的时钟类型具有不同的符号名称。因此,不能简单地写成#ifdef CLOCK_MONOTONIC_COARSE——必须知道该名称在所有系统中的所有别名,例如CLOCK_MONOTONIC_FAST 或其他。 未定义但实际支持时钟的情况并不少见——我现在在 openSUSE q31056979 中有它。当我刚开始研究其他系统并看到数值不同时,我试图做出假设。然后我意识到符号名称也不同。不,我完全被这种“标准化”弄糊涂了。

以上是关于clockid_t (clock_gettime 第一个参数) 可移植性的主要内容,如果未能解决你的问题,请参考以下文章

c++ clock_gettime() 和夏令时

Clock_Gettime() 抖动?

clock_gettime() 没有给出正确的输出[重复]

clock_gettime的介绍说明

clock_gettime的主要例子

使用clock_gettime在arduino中进行纳秒测量