timerfd是Linux中基于文件描述符的定时器机制,可通过epoll等I/O多路复用监控,实现线程安全的异步定时任务。

在Linux系统中,timerfd 是一种基于文件描述符的定时器机制,它允许你将定时事件集成到事件循环中(如 epoll),非常适合用于异步I/O编程。相比传统的信号驱动定时器(如setitimer或alarm),timerfd 更易于管理且线程安全。
什么是 timerfd?
timerfd 是 Linux 提供的一种机制,通过创建一个文件描述符来表示一个定时器。当定时器超时时,该描述符变为可读状态,你可以从它读取到期次数。这使得它可以与 select、poll 或 epoll 等I/O多路复用机制结合使用。
主要相关系统调用包括:
- timerfd_create():创建一个新的 timerfd 文件描述符。
- timerfd_settime():设置定时器的超时时间和间隔。
- timerfd_gettime():获取当前定时器设置。
基本使用步骤
下面是一个使用 timerfd 实现周期性定时任务的完整示例,每秒触发一次事件,并与 epoll 配合使用。
代码示例:每秒打印一次消息
#include <sys/timerfd.h>
#include <sys/epoll.h>
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
int main() {
// 1. 创建 timerfd,使用 CLOCK_MONOTONIC 时钟
int tfd = timerfd_create(CLOCK_MONOTONIC, 0);
if (tfd == -1) {
perror("timerfd_create");
return 1;
}
// 2. 设置定时器:1秒后首次触发,之后每1秒触发一次
struct itimerspec timer;
timer.it_value.tv_sec = 1; // 第一次超时时间
timer.it_value.tv_nsec = 0;
timer.it_interval.tv_sec = 1; // 重复间隔
timer.it_interval.tv_nsec = 0;
if (timerfd_settime(tfd, 0, &timer, NULL) == -1) {
perror("timerfd_settime");
close(tfd);
return 1;
}
// 3. 创建 epoll 实例并添加 timerfd
int epfd = epoll_create1(0);
if (epfd == -1) {
perror("epoll_create1");
close(tfd);
return 1;
}
struct epoll_event ev, events[1];
ev.events = EPOLLIN;
ev.data.fd = tfd;
if (epoll_ctl(epfd, EPOLL_CTL_ADD, tfd, &ev) == -1) {
perror("epoll_ctl");
close(tfd);
close(epfd);
return 1;
}
printf("等待定时器触发...\n");
// 4. 主事件循环
for (;;) {
int n = epoll_wait(epfd, events, 1, -1); // 永久阻塞等待
if (n > 0 && events[0].data.fd == tfd) {
uint64_t expirations;
ssize_t s = read(tfd, &expirations, sizeof(expirations));
if (s != sizeof(expirations)) {
fprintf(stderr, "read from timerfd failed\n");
break;
}
printf("定时器触发,已过期 %lu 次\n", expirations);
}
}
close(tfd);
close(epfd);
return 0;
}编译和运行
将上述代码保存为 timerfd_example.c,然后使用以下命令编译:
运行程序:
```bash ./timerfd_example ```输出类似:
等待定时器触发... 定时器触发,已过期 1 次 定时器触发,已过期 1 次 ...
关键点说明
- CLOCK_MONOTONIC 不受系统时间调整影响,推荐用于定时任务。
- it_value 为0表示禁用定时器;非零则启动。
- it_interval 决定是否周期性触发:若为0,则只触发一次。
- 每次事件发生后必须 read timerfd,否则会持续报告就绪。
- 读取的数据是 uint64_t 类型,表示自上次 read 以来的超时次数。
应用场景
timerfd 常用于:
- 网络服务中的心跳检测
- 定时清理缓存或连接
- 事件驱动框架中的超时管理(如 Redis、Nginx 类似机制)
- 替代 signal-based 定时器,避免信号处理复杂性
基本上就这些。使用 timerfd 可以写出更清晰、更安全的定时逻辑,尤其适合高并发服务器编程场景。










