Linux提供给我们的定时器

timerfd_createtimerfd_settime 是 Linux 提供的用于创建和管理定时器的系统调用,属于 timerfdAPI 的一部分。它们允许用户空间程序通过文件描述符来使用内核定时器,非常适合需要高精度定时或与 I/O 多路复用(如 selectpollepoll)结合使用的场景。

1.timerfd_create

功能:创建一个定时器对象,并返回一个与之关联的文件描述符。

复制代码
#include <sys/timerfd.h>

int timerfd_create(int clockid, int flags);

参数

clockid 指定定时器使用的时钟类型
CLOCK_REALTIME 系统实时时钟(可受系统时间调整影响
CLOCK_MONOTONIC 单调递增时钟,不受系统时间调整影响
CLOCK_BOOTTIME CLOCK_MONOTONIC 类似,但包括系统挂起时间
flags 控制定时器的行为
TFD_NONBLOCK 设置文件描述符为非阻塞模式
TFD_CLOEXEC 设置文件描述符为 close-on-exec(执行 exec 时自动关闭)

返回值

  • 成功:返回一个文件描述符(用于后续操作)。

  • 失败:返回 -1,并设置 errno

2. timerfd_settime

**功能:**启动、停止或修改定时器的设置。

函数原型:

cpp 复制代码
#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.it_value 解释为绝对时间(而非相对时间)。

new_value:指向 struct itimerspec 结构体,用于设置定时器的初始值和间隔值。

cpp 复制代码
struct itimerspec {
    struct timespec it_interval;  // 定时器的间隔时间
    struct timespec it_value;     // 定时器的初始到期时间
};

struct timespec {
    time_t tv_sec;   // 秒
    long   tv_nsec;  // 纳秒
};
  • 如果 it_value 的两个字段都为 0,则停止定时器。

  • 如果 it_interval 的两个字段都为 0,则定时器只触发一次。

old_value:指向 struct itimerspec 结构体,用于返回之前的定时器设置(可以为NULL)。

返回值

成功:返回 0。

失败:返回 -1,并设置 errno。

示例:

cpp 复制代码
#include <sys/timerfd.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>

int main() {
    // 创建定时器
    int fd = timerfd_create(CLOCK_MONOTONIC, 0);
    if (fd == -1) {
        perror("timerfd_create");
        exit(EXIT_FAILURE);
    }

    // 设置定时器:1秒后首次触发,之后每2秒触发一次
    struct itimerspec new_value;
    new_value.it_value.tv_sec = 1;   // 初始到期时间:1秒
    new_value.it_value.tv_nsec = 0;
    new_value.it_interval.tv_sec = 2; // 间隔时间:2秒
    new_value.it_interval.tv_nsec = 0;

    if (timerfd_settime(fd, 0, &new_value, NULL) == -1) {
        perror("timerfd_settime");
        close(fd);
        exit(EXIT_FAILURE);
    }

    printf("定时器已启动,每2秒触发一次\n");

    // 读取定时器事件
    while (1) {
        uint64_t expirations;
        ssize_t s = read(fd, &expirations, sizeof(expirations));
        if (s != sizeof(expirations)) {
            perror("read");
            close(fd);
            exit(EXIT_FAILURE);
        }
        printf("定时器触发,次数:%lu\n", expirations);
    }

    close(fd);
    return 0;
}

关键点

  • 定时器精度:timerfd 使用纳秒级精度,适合高精度定时需求。

  • 与 I/O 多路复用结合:可以将 timerfd 的文件描述符添加到 epoll 或 select 中,实现定时器与其他 I/O 事件的统一处理。

  • 资源释放:使用完毕后,应调用 close(fd) 关闭文件描述符。

适用场景

  • 周期性任务调度。

  • 超时机制(如网络请求超时)。

  • 高精度定时任务(如多媒体播放、游戏循环)。

相关推荐
暗影凋落11 分钟前
docker-image 工具展示更详细镜像层内容
运维·docker·容器
深圳市爱派派智能科技有限公司24 分钟前
“进迭时空 RISC-V 集群服务器 CSB1-N10SPK3:10 节点 K3,600 TOPS 绿色算力“
运维·服务器·risc-v·k3·进迭时空·集群服务器
☆凡尘清心☆24 分钟前
Linux运维故障排查速查命令清单
linux·运维·服务器
QWEDDRFTG27 分钟前
机房供电安全
服务器
极客先躯28 分钟前
高级java每日一道面试题-2026年05月11日-实战篇[Docker]-如何容器化金融产品推荐系统?
java·运维·docker·容器·金融·高级面试·金融产品推荐系统
小泊客30 分钟前
友善R5C刷OpenWrt后RTL8822CE无线网卡显示“禁用”或“未激活”的完整解决方案
linux·github·运维开发
nvd1131 分钟前
GCP L4 Passthrough 负载均衡器“假死超时”深度排查复盘
运维·php·负载均衡
mounter62533 分钟前
跨内核实时更新:如何实现 hugetlbfs 巨页的无缝保留与恢复?
linux·linux kernel·kernel·kexec·liveupdate·kho
qeen8741 分钟前
【Linux】make/Makefile 自动化工具的介绍
linux·运维·服务器·自动化
朱容zr3331331 小时前
为什么推荐使用自增主键?使用UUID作为主键的优缺点是什么?
java·运维·数据库·后端·mysql·面试·性能优化