定时器在许多场景中非常有用,尤其是在需要精确定时或定时执行某些任务的情况下。而Linux专门为定时器提供了一套定时器接口。
timerfd_create
是 Linux 中用于创建定时器文件描述符的函数。这个功能主要是用来在指定的时间后或定时间隔内触发事件,适用于需要精确定时的应用。
#include <sys/timerfd.h>
int timerfd_create(int clockid, int flags);
clockid
:指定计时器所使用的时钟,可以是CLOCK_REALTIME
或CLOCK_MONOTONIC
。
CLOCK_REALTIME
:系统实时时钟,从1970-01-01 00:00:00 UTC计时。CLOCK_MONOTONIC
:系统启动后经过的时间,不受系统时间变化的影响。 flags
:可以是 0 或 TFD_NONBLOCK、TFD_CLOEXEC 的组合。
TFD_NONBLOCK
:使文件描述符在非阻塞模式下工作。TFD_CLOEXEC
:在执行 exec() 系统调用时自动关闭文件描述符。timerfd_create
的返回值是一个文件描述符,用于标识创建的定时器。如果创建成功,它返回一个非负的文件描述符;如果失败,它返回 -1,并设置 errno
来指示错误原因。
itimerspec
是一个结构体,用于指定定时器的初始启动时间和间隔时间。
该结构体定义在头文件 <time.h>
中,结构如下:
struct itimerspec {
struct timespec it_interval; /* Interval for periodic timer */
struct timespec it_value; /* Initial expiration */
};
it_interval
:指定定时器的周期。如果定时器是单次触发,这个值应为 0。it_value
:指定定时器的初始启动时间。其中
timerfd_settime
函数)后开始计时,到第一次触发之间的时间间隔。timespec
结构体itimerspec
中包含的两个字段 it_interval
和 it_value
均是 timespec
结构体类型。timespec
结构体定义如下:
struct timespec {
time_t tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
tv_sec
:以秒为单位的时间。tv_nsec
:以纳秒为单位的时间。timerfd_settime
timerfd_settime
是用于设置和启动定时器的函数,它与 timerfd_create
一起使用来控制定时器的行为。timerfd_settime
函数允许你指定定时器的初始启动时间和周期时间。
int timerfd_settime(int fd, int flags,
const struct itimerspec *new_value,
struct itimerspec *old_value);
fd
:由timerfd_create
返回的定时器文件描述符。flags
:指定定时器的行为,可以是以下值之一:
0
:相对时间,从当前时间开始计时。TFD_TIMER_ABSTIME
:绝对时间,从指定的时间点(即从 UNIX 纪元(1970年1月1日)以来的秒数和纳秒数)开始计时。 new_value
:指向一个 itimerspec
结构体,定义定时器的初始启动时间和周期时间。
old_value
:如果不为 NULL,该结构体将保存上一次的定时器设定值。
定时器的设置可以涉及两种主要的时间表示方式:
当使用 TFD_TIMER_ABSTIME
标志时,it_value
代表的是一个绝对时间点,即从 UNIX 纪元(1970年1月1日)以来的秒数和纳秒数。因此,定时器将从当前时间加上 it_value
指定的时间点开始计时。
timerfd_gettime
timerfd_gettime
是一个系统调用函数,用于获取定时器的当前状态,包括定时器的剩余时间和定时器的周期时间。这个函数对于检查定时器的状态或获取定时器当前剩余的时间非常有用。
int timerfd_gettime(int fd, struct itimerspec *curr_value);
fd
:定时器文件描述符,是通过timerfd_create
创建的。curr_value
(输出型参数):指向itimerspec
结构体的指针,用于接收定时器的当前状态。itimerspec
结构体包括:
it_value
:定时器的剩余时间(即下次到期时间的时间点)。it_interval
:定时器的周期时间。0
。-1
并设置 errno
以指示错误类型。clock_gettime
int clock_gettime(clockid_t clk_id, struct timespec *tp);
clk_id
:时钟标识符,指定要获取时间的时钟。常见的时钟类型包括: CLOCK_REALTIME
:系统实时时钟,表示当前的系统时间,从 UNIX 纪元(1970年1月1日)以来的秒数。CLOCK_MONOTONIC
:单调时钟,表示系统启动以来的时间,不受系统时间调整的影响。CLOCK_PROCESS_CPUTIME_ID
:当前进程的 CPU 时间。CLOCK_THREAD_CPUTIME_ID
:当前线程的 CPU 时间。tp
:指向 timespec
结构体的指针,用于接收获取的时间信息。0
。-1
并设置 errno
以指示错误类型。#include <iostream>
#include <sys/timerfd.h>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include <ctime>
int main() {
// 创建 timerfd
int timerfd = timerfd_create(CLOCK_REALTIME, 0);
if (timerfd == -1) {
std::cerr << "Failed to create timerfd: " << strerror(errno) << std::endl;
return 1;
}
// 设置定时器
struct itimerspec new_value;
new_value.it_value.tv_sec = 5; // 初始启动时间为5秒后
new_value.it_value.tv_nsec = 0;
new_value.it_interval.tv_sec = 1; // 周期为1秒
new_value.it_interval.tv_nsec = 0;
if (timerfd_settime(timerfd, 0, &new_value, NULL) == -1) {
std::cerr << "Failed to set timer: " << strerror(errno) << std::endl;
close(timerfd);
return 1;
}
// 获取定时器状态
struct itimerspec curr_value;
if (timerfd_gettime(timerfd, &curr_value) == -1) {
std::cerr << "Failed to get timer time: " << strerror(errno) << std::endl;
close(timerfd);
return 1;
}
// 输出当前状态
std::cout << "Current timer status:" << std::endl;
std::cout << "Time until next expiration (seconds): " << curr_value.it_value.tv_sec << std::endl;
std::cout << "Time until next expiration (
timerfd_create
创建一个定时器文件描述符。
timerfd_settime
配置定时器的初始启动时间和周期时间。
timerfd_gettime
获取定时器的当前状态,将结果存储在 curr_value
中。curr_value
是一个 itimerspec
结构体,它会被填充为定时器的剩余时间和周期时间。
定时器在许多应用场景中都非常有用,特别是在需要精确时间控制和事件调度的情况下。以下是一些常见的使用场景:
CLOCK_REALTIME
用于实际时间触发,CLOCK_MONOTONIC
用于系统启动后的持续时间触发,不受系统时间修改的影响。timerfd_gettime
检查定时器的当前状态,确保定时器运行如预期。