一、timerfd系列的定时函数

#include <sys/timerfd.h>
int timerfd_create(int clockid, int flags);
int timerfd_settime(int fd, int flags, const struct itimerspec *new_value, struct itimerspec *old_value);
int timerfd_gettime(int fd, struct itimerspec *curr_value);

timerfd_create函数创建定时器对象,这个定时器对象与返回值timerfd进行绑定。

第一个参数clockid如果指定为 CLOCK_REALTIME 时表示定时器为实时系统时钟,如果指定为CLOCK_MONOTONIC 表示一个相对单调递增的时钟;

第二个参数flags可以指定为TFD_NONBLOCK或者 TFD_CLOEXEC

timerfd_settime函数可以设置定时器对象

第一个参数就是timerfd_create函数的返回值

第二个参数指定为0时表示启动相对定时器(此时第三个参数new_value.it_value就要指定为相对时间,假如当前时间为8:00,希望定时器在8:10响的话就设置new_value.it_value为10分钟

当指定为TFD_TIMER_ABSTIME表示绝对定时器(第三个参数new_value.it_value要指定为绝对时间,希望定时器在8:10响的话就指定new_value.it_value为8:10

timerfd_gettime函数的第1个参数是timerfd_create函数的返回值,第二个参数curr_value.it_value表示当前时间到第一次触发剩余的时间。


1、 timerfd_create, timerfd_settime read函数举例:首先设置单次触发定时器,就是设置 struct itimerspec new_value 结构体的成员new_value.it_interval.tv_sec new_value.it_interval.tv_nsec 的值为0

#define _POSIX_C_SOURCE 199309L

#include <sys/timerfd.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>

#define handle_error(msg) \
       do { perror(msg); exit(EXIT_FAILURE); } while (0)

int main(void)
{
    uint64_t exp = 0;
    int timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); 
    if (timerfd == -1)
    {
        handle_error("timerfd_create");
    }

    struct itimerspec new_value = {};
    new_value.it_value.tv_sec  = 10; // 2s
    new_value.it_value.tv_nsec = 0;
    
    new_value.it_interval.tv_sec  = 0; // one shot
    new_value.it_interval.tv_nsec = 0;

    /*启动timerfd绑定的定时器,0表示启动相对定时器,时间=当前时间+new_value.it_value,NULL表示旧的定时值*/
    if (timerfd_settime(timerfd, 0, &new_value, NULL) == -1) 
    {
        handle_error("timerfd_settime");
    }

    printf("timer started\n");

    while (1)
    {
        int ret = read(timerfd, &exp, sizeof(uint64_t));
        
        if (ret == sizeof(uint64_t)) // 
        {
            printf("ret: %d\n", ret);
            printf("expired times: %llu\n", exp);
            break;
        }
    }

    return 0;

}

2、如果设置 struct itimerspec new_value 结构体的成员new_value.it_interval.tv_sec = 5, new_value.it_interval.tv_nsec = 0,使得第一次触发后每隔5s再触发一次。

 

二、Epoll和Timerfd组合使用

#include <sys/epoll.h>
#include <sys/timerfd.h>
#include <time.h>
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
 
#define MX_EVNTS 10
#define EPL_TOUT 3000
#define MX_CNT 5
 
struct param{
    struct itimerspec its;
    int tfd;
};
 
void *strt_eplth(void *arg)
{
    struct epoll_event evnts[MX_EVNTS];
    int *eplfd = (int *)arg;
    int n = -1;
    size_t i,cnt = 0;
    while(1){
        n = epoll_wait(*eplfd,evnts,MX_EVNTS,EPL_TOUT);
        if(n == -1){
            perror("epoll_wait() error");
            break;
        }else if(n == 0){
            printf("time out %d sec expired\n",EPL_TOUT / 1000);
            break;
        }
        for(i = 0; i < n;i++){
            struct param *pm = (struct param *)(evnts[i].data.ptr);
            printf("tfd: %d\ninitial expiration: %ld\ninterval: %ld\n\n",
                pm->tfd,
                (long)(pm->its.it_value.tv_sec),
                (long)(pm->its.it_interval.tv_sec));
            if(epoll_ctl(*eplfd,EPOLL_CTL_DEL,pm->tfd,NULL) != 0){
                perror("epoll_ctl(DEL) error in thread");
                break;
            }
            struct epoll_event ev;
            ev.events = EPOLLIN | EPOLLET;
            pm->its.it_value.tv_sec =
                pm->its.it_value.tv_sec +
                pm->its.it_interval.tv_sec;
            ev.data.ptr = pm;
            if(timerfd_settime(pm->tfd,TFD_TIMER_ABSTIME,&(pm->its),NULL) != 0){
                perror("timerfd_settime() error in thread");
                break;
            }
            if(epoll_ctl(*eplfd,EPOLL_CTL_ADD,pm->tfd,&ev) != 0){
                perror("epoll_ctl(ADD) error in thread");
                break;
            }
        }
        if(++cnt == MX_CNT){
            printf("cnt reached MX_CNT, %d\n",MX_CNT);
            break;
        }
    }
    close(*eplfd);
    pthread_exit(NULL);
}
 
int create_timerfd(struct itimerspec *its,time_t interval)
{
    int tfd = timerfd_create(CLOCK_MONOTONIC,TFD_NONBLOCK);
    if(tfd < 0){
        perror("timerfd_create() error");
        return -2;
    }
    struct timespec nw;
    if(clock_gettime(CLOCK_MONOTONIC,&nw) != 0){
        perror("clock_gettime() error");
        return -1;
    }
    its->it_value.tv_sec = nw.tv_sec + interval;
    its->it_value.tv_nsec = 0;
    its->it_interval.tv_sec = interval;
    its->it_interval.tv_nsec = 0;
    return tfd;
}
 
int main()
{
    time_t INTERVAL = 2;
    struct itimerspec its;
    int tfd = create_timerfd(&its,INTERVAL);
    if(tfd < 0)
        return -1;
    int eplfd = epoll_create1(0);
    if(eplfd < 0){
        perror("epoll_create1() error");
        return -1;
    }
    struct param pm;
    pm.its = its;
    pm.tfd = tfd;
    if(timerfd_settime(pm.tfd,TFD_TIMER_ABSTIME,&(pm.its),NULL) != 0){
        perror("timerfd_settime() error");
        return -1;
    }
    struct epoll_event ev;
    ev.events = EPOLLIN | EPOLLET;
    ev.data.ptr = &pm;
    if(epoll_ctl(eplfd,EPOLL_CTL_ADD,pm.tfd,&ev) != 0){
        perror("epoll_ctl() error");
        return -1;
    }
    pthread_t pid;
    if(pthread_create(&pid,NULL,strt_eplth,(void *)&eplfd) != 0){
        perror("pthread_create() error");
        return -1;
    }
 
    //// add another timerfd.
    INTERVAL = 1;
    struct itimerspec its2;
    int tfd2 = create_timerfd(&its2,INTERVAL);
    if(tfd2 < 0)
        return -1;
    struct param pm2;
    pm2.its = its2;
    pm2.tfd = tfd2;
    if(timerfd_settime(pm2.tfd,TFD_TIMER_ABSTIME,&(pm2.its),NULL) != 0){
        perror("timerfd_settime() error");
        return -1;
    }
    struct epoll_event ev2;
    ev2.events = EPOLLIN | EPOLLET;
    ev2.data.ptr = &pm2;
    if(epoll_ctl(eplfd,EPOLL_CTL_ADD,pm2.tfd,&ev2) != 0){
        perror("epoll_ctl() error");
        return -1;
    }
 
    if(pthread_join(pid,NULL) != 0){
        perror("pthread_join() error");
        return -1;
    }
    close(tfd);
    close(tfd2);
    return 0;
}

 

(37条消息) Linux下定时函数timerfd_xxx()的使用_爱就是恒久忍耐的博客-CSDN博客

(37条消息) struct timespec 和 struct timeval_思泽之思的博客-CSDN博客

Linux定时器timerfd用法 - 明明1109 - 博客园 (cnblogs.com)

Epoll+Timerfd实现定时器 | 趣果有间

posted on 2023-04-12 16:18  轩~邈  阅读(581)  评论(0)    收藏  举报