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) 关闭文件描述符。

适用场景

  • 周期性任务调度。

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

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

相关推荐
编织幻境的妖7 分钟前
关于阿里云 dataworks 运维中心下的任务运维的问题
java·运维·阿里云
小镇敲码人11 分钟前
【Linux网络编程】之配置阿里云安全组
linux·网络·阿里云
Azure DevOps22 分钟前
Azure DevOps Server(TFS):旧版本即将停止支持
运维·microsoft·azure·devops·tfs
Golinie23 分钟前
【Linux网络编程】谈谈网络编程中的select、poll、epoll、Reactor、Proactor模型(下)
linux·网络·reactor·epoll·io多路复用
飞翔的煤气罐boom35 分钟前
TCP服务器与客户端搭建
linux·tcp/ip·c
小林熬夜学编程38 分钟前
【MySQL】第二弹---数据库基础全解析:从概念到实践的深度探索
linux·开发语言·数据库·mysql·算法
相醉为友1 小时前
005 嵌入式Linux应用开发——文件操作
linux·笔记
_GR1 小时前
Redis存储⑤Redis五大数据类型之 List 和 Set。
linux·数据库·redis·ubuntu·缓存
张声录11 小时前
DeepSeek本地化部署【window下安装】【linux下安装】
linux·运维·服务器
F——2 小时前
2025 IT职业发展方向及推荐
运维·数据库·学习·云计算·边缘计算