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#include #include #include #include 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 可以写出更清晰、更安全的定时逻辑,尤其适合高并发服务器编程场景。










