timerfd_create
函数简介
timerfd_create
是 Linux 提供的一个系统调用,用于创建一个文件描述符,用来触发定时器事件。可以通过该文件描述符来监视定时器到期事件,例如用 poll
或 select
进行事件检测。这种机制常用于高效的事件驱动型程序。
函数原型
#include <sys/timerfd.h>
int timerfd_create(int clockid, int flags);
clockid
: 指定定时器使用的时钟,可以是以下值:CLOCK_REALTIME
: 基于系统的实时时钟,受系统时间改变影响。CLOCK_MONOTONIC
: 基于系统的单调时钟,不受系统时间改变影响。
flags
: 指定文件描述符的行为,常用值:0
: 默认行为。TFD_NONBLOCK
: 非阻塞模式。TFD_CLOEXEC
:exec
时自动关闭文件描述符。
返回值:
- 成功时返回定时器文件描述符(一个正整数)。
- 失败时返回
-1
,并设置errno
。
定时器设置:timerfd_settime
要设置定时器,可以使用以下函数:
#include <sys/timerfd.h>
int timerfd_settime(int fd, int flags,
const struct itimerspec *new_value,
struct itimerspec *old_value);
fd
: 使用timerfd_create
创建的文件描述符。flags
: 通常为0
。若设置为TFD_TIMER_ABSTIME
,则定时器以绝对时间计算。new_value
: 指定定时器的新值,使用struct itimerspec
结构。old_value
: 如果不为NULL
,则保存定时器的旧值。
struct itimerspec
结构:
struct itimerspec {
struct timespec it_interval; // 定时器的间隔时间
struct timespec it_value; // 定时器的初始到期时间
};
示例代码
以下代码展示了如何使用 timerfd_create
创建一个定时器,并通过 poll
等待定时器事件:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/timerfd.h>
#include <sys/poll.h>
#include <time.h>
#include <stdint.h> // for uint64_t
int main() {
int timer_fd;
struct itimerspec new_timer;
// 创建一个基于单调时钟的定时器
timer_fd = timerfd_create(CLOCK_MONOTONIC, 0);
if (timer_fd == -1) {
perror("timerfd_create failed");
exit(EXIT_FAILURE);
}
// 设置定时器:2秒后触发,然后每隔1秒触发一次
new_timer.it_value.tv_sec = 2; // 首次触发的时间(秒)
new_timer.it_value.tv_nsec = 0; // 首次触发的时间(纳秒)
new_timer.it_interval.tv_sec = 1; // 每次触发的间隔时间(秒)
new_timer.it_interval.tv_nsec = 0; // 每次触发的间隔时间(纳秒)
if (timerfd_settime(timer_fd, 0, &new_timer, NULL) == -1) {
perror("timerfd_settime failed");
exit(EXIT_FAILURE);
}
printf("Timer started! It will fire in 2 seconds, then every 1 second.\n");
// 使用 poll 监视定时器文件描述符
struct pollfd poll_fds;
poll_fds.fd = timer_fd;
poll_fds.events = POLLIN; // 等待定时器可读事件
while (1) {
int ret = poll(&poll_fds, 1, -1); // 无限等待
if (ret == -1) {
perror("poll failed");
exit(EXIT_FAILURE);
}
if (poll_fds.revents & POLLIN) {
uint64_t expirations;
ssize_t s = read(timer_fd, &expirations, sizeof(expirations));
if (s != sizeof(expirations)) {
perror("read failed");
exit(EXIT_FAILURE);
}
printf("Timer expired %llu times\n", (unsigned long long) expirations);
}
}
close(timer_fd);
return 0;
}
代码说明
- 创建定时器:
- 使用
timerfd_create
创建一个基于CLOCK_MONOTONIC
的定时器。
- 使用
- 设置定时器:
- 使用
timerfd_settime
设置首次触发时间为 2 秒,之后每隔 1 秒触发一次。
- 使用
- 等待定时器事件:
- 使用
poll
等待定时器文件描述符的可读事件。 - 每当定时器触发,文件描述符变为可读,通过
read
读取定时器触发的次数。
- 使用
- 输出结果:
- 每次定时器触发时,输出触发的次数。
示例运行
运行上述代码,输出如下:
Timer started! It will fire in 2 seconds, then every 1 second.
Timer expired 1 times
Timer expired 1 times
Timer expired 1 times
...
优点
- 可以高效地监控多个定时器文件描述符,与
epoll
或poll
配合使用适合事件驱动编程。 - 使用单调时钟(
CLOCK_MONOTONIC
)不受系统时间修改的影响,非常适合定时任务。
注意事项
- 文件描述符需要在程序结束时关闭(
close
)。 - 定时器间隔为
0
时,表示单次触发定时器。