POSIX 时间 API

最后更新: 2023-08-09 17:37:46 +0800 +0800
tags: Linux | Posix | Time
原文以英文撰写。您正在阅读AI翻译版本。

时间 API 回答不同问题:民用时间为某个时刻命名,单调时间测量间隔,CPU 时钟测量工作消耗的执行时间。选择错误的时钟会使超时响应墙上时钟校正,或使 I/O 等待从测量结果中消失。

选择时钟 #

clock_gettime 将 clockid_t 读取到 struct timespec 中,其中 tv_sec 和 tv_nsec 字段分别表示秒和纳秒。POSIX 要求提供 CLOCK_REALTIME(从纪元开始计量的系统民用时钟)和 CLOCK_MONOTONIC(起点未指定且不能设置)。时间戳使用 realtime,经过时间和截止时间使用单调时间。

在受支持时,CLOCK_PROCESS_CPUTIME_ID 和 CLOCK_THREAD_CPUTIME_ID 分别测量进程或单个线程消耗的 CPU 执行时间。它们不包括阻塞在 I/O 中或被取消调度的时间。Linux 还提供包含挂起时间的 CLOCK_BOOTTIME;这是 Linux 扩展,而不是可移植的 POSIX 选择。

c
struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);
/* operation */
clock_gettime(CLOCK_MONOTONIC, &end);

clock_getres 报告实现的分辨率,而不是保证连续读取会产生不同结果。调度延迟、定时器合并和硬件都会影响代码运行的时刻。当某个时刻无法放入 time_t 时,调用可能以 EOVERFLOW 失败;应验证 tv_nsec,规范化跨秒边界的算术运算,并且不要假设 time_t 具有固定宽度。

睡眠与定时器 #

nanosleep 提供相对延迟。信号可以以 EINTR 中断它并报告剩余时间,但在周期性代码中从剩余时间重新开始仍会累积工作和调度延迟。每个周期计算一个绝对的单调截止时间,并使用 clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, ...) 等待;已经过去的截止时间会立即返回,因此调用方必须决定跳过工作还是追赶进度。

POSIX 定时器使用 timer_create 和 timer_settime;TIMER_ABSTIME 使请求的到期时间成为定时器所选时钟上的绝对时间。通知可以是信号或线程通知,两者具有不同的排队和生命周期影响。Linux 的 timerfd_create 不是 POSIX 接口,但可以将定时器到期与 poll、select 和 epoll 集成。alarm 和 setitimer 是面向信号的旧接口。

相对等待不会受到之后 CLOCK_REALTIME 调整的影响,而绝对 realtime 截止时间会随该时钟移动。因此,除非产品需求明确要求“在这个民用时间时刻”,否则应在单调时钟上表示超时截止时间。

民用时间与时区 #

time_t 是标量时间值;struct tm 是分解后的日历时间。gmtime_r 将其转换为 UTC,localtime_r 根据进程时区规则进行转换。它们不带 _r 的对应函数使用可复用的静态存储。mktime 将 struct tm 解释为本地民用时间;将 tm_isdst 设置为 -1 可以让它确定夏令时状态。timegm 是用于解释分解后 UTC 的实用 GNU 扩展,不是 POSIX 接口。

TZ 和 tzset 控制进程的时区状态。秋季夏令时转换期间的本地时间可能对应两个时刻;春季跳过的本地时间可能不对应任何时刻。以 UTC 或 time_t 存储时刻;当面向人类的值必须保留其民用时间含义时,携带显式的时区或偏移量。

POSIX 时间不会将闰秒建模为独立的标量时间秒。系统同步时可能调整或平滑 realtime 时钟;因此,仅靠 time_t 算术或 UTC 转换 API 都不能完整表示闰秒。

POSIX 时钟规范 和 clock_nanosleep(3) 定义了可移植及 Linux 特定的细节。

评论

在 GitHub 上阅读或评论(发表评论需要登录)