timerfd 定时器类函数

文章介绍了Linux中的timerfd机制,这是一个基于文件描述符的定时器接口,可用于配合select、poll、epoll等I/O多路复用方法。主要函数包括timerfd_create用于创建定时器,timerfd_settime设置超时时间和间隔,以及timerfd_gettime获取剩余时间。示例程序展示了如何结合epoll使用timerfd处理超时事件。
摘要由CSDN通过智能技术生成
        timerfd 是 Linux 为用户程序提供的一个定时器接口。这个接口基于文件描述符,通过文件描述符的可读事件进行超时通知,因此可以配合 select/poll/epoll 等使用。

timerfd_create 创建定时器对象函数

头文件:
#include <sys/timerfd.h>
函数原型:
int timerfd_create(int clockid, int flags);
作用:
        创建一个定时器对象,同时返回一个与之关联的文件描述符
参数含义:
        clockid: 标识指定的时钟计数器,可选值 CLOCK_REALTIME、CLOCK_MONOTONIC…
                CLOCK_REALTIME: 系统实时时间 , 随系统实时时间改变而改变 , 即从 UTC1970-1-1 0:0:0 开始计时 , 中间时刻如果系统时间被用户改成其他 , 则对应的时间相应改变
                CLOCK_MONOTONIC : 从系统启动这一刻起开始计时 , 不受系统时间被用户改变的影
        flags:可以为 0 或 TFD_NONBLOCK,TFD_CLOEXEC。0 表示无属性,TFD_NONBLOCK表示设置为非阻塞模式,TFD_CLOEXEC 表示当程序执行 exec 函数时本 fd 将被系统自动关闭 , 表示不传递. 2.6.26 之前的 Linux 版本中,标志必须指定为零。
返回值:
        如果成功返回一个定时器的文件描述符,失败返回-1

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: 设置为 1 代表设置的是绝对时间;为 0 代表相对时间。
        new_value: 参数 new_value 指定定时器的超时时间以及超时间隔时间 , new_value.it_value 非零则启动定时器,否则关闭定时器,如果 new_value.it_interval 为0,则定时器只定时一次,即初始那次,否则之后每隔设定时间超时一次
        old_value: 不为 null ,则返回定时器这次设置之前的超时时间
struct itimerspec
{
    struct timespec it_interval; //定时间隔周期
    struct timespec it_value; //第一次超时时间
};
struct timespec
{
    __time_t tv_sec; /* 秒. */
    __syscall_slong_t tv_nsec; /* 纳秒. */
};
返回值:
        成功返回 0,失败返回-1

timerfd_gettime 获取距离下次超时的剩余时间

头文件:
#include <sys/timerfd.h>
函数原型:
int timerfd_gettime(int fd, struct itimerspec *curr_value);
作用:
        获取距离下次超时剩余的时间
参数含义:
        fd: timerfd_create 函数返回的文件句柄
        curr_value: curr_value.it_value 字段表示距离下次超时的时间,如果该值为 0 ,表示计时器已经解除, 改字段表示的值永远是一个相对值,无论 TFD_TIMER_ABSTIME 是否被设置. curr_value.it_interval 定时器间隔时间
返回值:
        成功返回 0,失败返回-1
read 读取 timefd 超时事件通知
        当定时器超时,read 读事件发生即可读,返回超时次数(从上次调用timerfd_settime()启动开始或上次 read 成功读取开始),它是一个 8 字节的 unit64_t 类型整数,如果定时器没有发生超时事件,则 read 将阻塞若 timerfd 为阻塞模式,否则返回EAGAIN 错误( O_NONBLOCK 模式),如果 read 时提供的缓冲区小于 8 字节将以EINVAL 错误返回。

示例程序

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
#include <sys/epoll.h>
#include <sys/timerfd.h>
#include <unistd.h>

#define EPOLL_LISTEN_CNT 256
#define EPOLL_LISTEN_TIMEOUT 500

static int g_epollfd = -1;
static int g_timerfd = -1;

uint64_t tot_exp = 0;

static void print_elapsed_time(void)
{
    static struct timespec start;
    struct timespec curr;
    static int first_call = 1;
    int secs, nsecs;
    if (first_call) 
    {
        first_call = 0;
        if (clock_gettime(CLOCK_MONOTONIC, &start) == -1)
            printf("clock_gettime\n");
    }
    if (clock_gettime(CLOCK_MONOTONIC, &curr) == -1)
        printf("clock_gettime\n");
    secs = curr.tv_sec - start.tv_sec;
    nsecs = curr.tv_nsec - start.tv_nsec;
    if (nsecs < 0) 
    {
        secs--;
        nsecs += 1000000000;
    }
    printf("%d.%03d: ", secs, (nsecs + 500000) / 1000000);
}

void timerfd_handler(int fd)
{
    uint64_t exp = 0;
    read(fd, &exp, sizeof(uint64_t));
    tot_exp += exp;
    print_elapsed_time();
    printf("read: %llu, total: %llu\n", (unsigned long long)exp, (unsigned long long)tot_exp);
    return;
}

void epoll_event_handle(void)
{
    int i = 0;
    int fd_cnt = 0;
    int sfd;
    struct epoll_event events[EPOLL_LISTEN_CNT]; 
    memset(events, 0, sizeof(events));
    while(1) 
    { 
        /* wait epoll event */
        fd_cnt = epoll_wait(g_epollfd, events, EPOLL_LISTEN_CNT,EPOLL_LISTEN_TIMEOUT); 
        for(i = 0; i < fd_cnt; i++) 
        { 
            sfd = events[i].data.fd;
            if(events[i].events & EPOLLIN) 
            { 
                if (sfd == g_timerfd) 
                {
                    timerfd_handler(sfd); 
                } 
            } 
        } 
    } 
}

int epoll_add_fd(int fd)
{
    int ret;
    struct epoll_event event;
    memset(&event, 0, sizeof(event));
    event.data.fd = fd;
    event.events = EPOLLIN | EPOLLET;
    ret = epoll_ctl(g_epollfd, EPOLL_CTL_ADD, fd, &event);
    if(ret < 0) 
    {
        printf("epoll_ctl Add fd:%d error, Error:[%d:%s]\n", fd, errno,strerror(errno));
        return -1;
    }
    printf("epoll add fd:%d--->%d success\n", fd, g_epollfd);
    return 0; 
}

int epollfd_init()
{
    int epfd;
    /* create epoll fd */
    epfd = epoll_create(EPOLL_LISTEN_CNT); 
    if (epfd < 0) 
    {
        printf("epoll_create error, Error:[%d:%s]\n", errno, 
        strerror(errno));
        return -1;
    }
    g_epollfd = epfd;
    printf("epoll fd:%d create success\n", epfd);
    return epfd;
}

int timerfd_init()
{
    int tmfd;
    int ret;
    struct itimerspec new_value;
    new_value.it_value.tv_sec = 2;
    new_value.it_value.tv_nsec = 0;
    new_value.it_interval.tv_sec = 1;
    new_value.it_interval.tv_nsec = 0;
    tmfd = timerfd_create(CLOCK_MONOTONIC, 0);
    if (tmfd < 0) 
    {
        printf("timerfd_create error, Error:[%d:%s]\n", errno, 
        strerror(errno));
        return -1;
    }
    ret = timerfd_settime(tmfd, 0, &new_value, NULL);
    if (ret < 0) 
    {
        printf("timerfd_settime error, Error:[%d:%s]\n", errno, 
        strerror(errno));
        close(tmfd);
        return -1;
    }
    if (epoll_add_fd(tmfd)) 
    {
        close(tmfd);
        return -1;
    }
    g_timerfd = tmfd;
    return 0;
}

int main(int argc, char **argv)
{
    if (epollfd_init() < 0) 
    {
        return -1;
    }
    if (timerfd_init()) 
    {
        return -1;
    }
    /* event handle */
    epoll_event_handle();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

九月丫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值