Linux环境编程 用户层定时器使用一 timerfd的使用

timerfd是linux提供的定时器机制,基于文件描述符,定时器精度最高可达纳秒级别,接口包括定时器创建、启动定时器、关闭定时器和删除定时器。下面介绍一下timerfd  API接口和一个结合epoll使用的定时器demo。

1. 创建定时器 

#include <sys/timerfd.h>
/*
 * 功能 : 创建定时器
 * 返回值:成功返回定时器文件描述符,失败返回-1
 * 参数:  clockid可以是CLOCK_REALTIME(实时时钟)或者CLOCK_MONOTONIC(递增时钟),实时时钟可以被系统时间改变,后者不会。
 * 				 如果这里使用实时时钟,当手动更改系统时间定时器也会受影响,而递增时钟则只受设置的时间值影响。
 * flags : 可选项包括TFD_NONBLOCK(非阻塞)和TFD_CLOEXEC,阻塞指的是当定时器未超时的时候,如果调用read(timerfd)会阻塞直
 *  				到定时器超时,如果设置TFD_NONLOCK,则会直接返回并返回-1. 这与套接字描述符类似。
 */
int timerfd_create(int clockid, int flags);             				 如果这里使用实时时钟,当手动更改系统时间定时器也会受影响,而递增时钟则只受设置的时间值影响。
 * flags : 可选项包括TFD_NONBLOCK(非阻塞)和TFD_CLOEXEC,阻塞指的是当定时器未超时的时候,如果调用read(timerfd)会阻塞直
 *  				到定时器超时,如果设置TFD_NONLOCK,则会直接返回并返回-1. 这与套接字描述符类似。
 */
int timerfd_create(int clockid, int flags);             
            

2. 启动和停止定时器

/*
 * 功能 定时器启动和关闭
 * 返回值 : 成功返回0,失败返回-1,并存储错误码到errno
 * 参数: fd: 定时器描述符
 *	 flags: 0 或者TFD_TIMER_ABSTIME,0代表相对时间,即相对于当前时间多少,后者是绝对时间。
 * 	 new_value: 当new_value.it_value非0时,用于设置定时器第一次超时时间,为0代表停止定时器
		    new_value.it_interval:表示第一次超时后下一次超时的时间,为0代表定时器只超时一次
 *	 old_value: 如果不为NULL,则用来存储当前时间。

int timerfd_settime(int fd, int flags, const struct itimerspec *new_value, struct itimerspec *old_value);  

3. 关闭定时器

/*
 * 功能: 和普通描述符一样,用完后使用close释放
 * 参数:timerfd为timerfd_create()创建的定时器描述符
 */
close(timerfd);

4. 时间结构体

struct timespec {
    time_t tv_sec;                /* Seconds */
    long   tv_nsec;               /* Nanoseconds */
};

struct itimerspec {
    struct timespec it_interval;  /* Interval for periodic timer */
    struct timespec it_value;     /* Initial expiration */
};

下面是一个结合epoll使用的定时器demo,创建一个每隔2s超时的定时器并加入到epoll监听队列中,每当定时器到期超时时产生一个读事件,之后可以去执行相应的定时器回调函数。

/*
 *  Description : linux 应用层编程之定时器timerfd的使用
 *  Date        :20180611
 *  Author      :mason
 *  Mail        : mrsonko@126.com
 *
 */

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

#define TIME_MAX 2 
#define log(fmt, arg...) printf(""fmt, ##arg)

void main() {
    int tfd;    //定时器描述符
    int efd;    //epoll描述符
    int fds, ret;
    uint64_t value;
    struct epoll_event ev, *evptr;
    struct itimerspec time_intv; //用来存储时间

    tfd = timerfd_create(CLOCK_MONOTONIC, 0);   //创建定时器
    if(tfd == -1) {
        log("create timer fd fail \r\n");
        return ;
    }

    time_intv.it_value.tv_sec = TIME_MAX; //设定2s超时
    time_intv.it_value.tv_nsec = 0;
    time_intv.it_interval.tv_sec = time_intv.it_value.tv_sec;   //每隔2s超时
    time_intv.it_interval.tv_nsec = time_intv.it_value.tv_nsec;

    log("timer start ...\n");
    timerfd_settime(tfd, 0, &time_intv, NULL);  //启动定时器
    
    efd = epoll_create1(0); //创建epoll实例
    if (efd == -1) {
        log("create epoll fail \r\n");
        close(tfd);
        return ;
    }
    
    evptr = (struct epoll_event *)calloc(1, sizeof(struct epoll_event));
    if (evptr == NULL) {
        log("epoll event calloc fail \r\n");
        close(tfd);
        close(efd);
        return ;
    }

    ev.data.fd = tfd; 
    ev.events = EPOLLIN;    //监听定时器读事件,当定时器超时时,定时器描述符可读。
    epoll_ctl(efd, EPOLL_CTL_ADD, tfd, &ev); //添加到epoll监听队列中

    while(1) {
        fds = epoll_wait(efd, evptr, 1, -1);    //阻塞监听,直到有事件发生
        if(evptr[0].events & EPOLLIN){   
                ret = read(evptr->data.fd, &value, sizeof(uint64_t));
                if (ret == -1) 
                    log("read return -1, errno :%d \r\n", errno);
                else
                    log("*** timer up  *** \n");               
       }            
    }

    return ;
}

实验截图:

代码路径:

git@github.com:FuYuanDe/timerfd.git

参考资料:

https://linux.die.net/man/2/timerfd_create

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux使用C++实现定时器,你可以使用以下步骤: 1. 包含所需的头文件: ```cpp #include <iostream> #include <unistd.h> #include <signal.h> ``` 2. 编写一个信号处理函数,用于处理定时器触发事件: ```cpp void timerHandler(int signum) { // 在这里编写定时器触发时要执行的代码 std::cout << "Timer triggered!" << std::endl; } ``` 3. 在主函数中设置定时器: ```cpp int main() { // 创建一个定时器 timer_t timer; // 定义定时器的配置 struct sigevent sev; sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = SIGALRM; sev.sigev_value.sival_ptr = &timer; // 创建定时器 timer_create(CLOCK_REALTIME, &sev, &timer); // 设置定时器的超时时间和间隔时间(这里设定为1秒) struct itimerspec its; its.it_value.tv_sec = 1; its.it_value.tv_nsec = 0; its.it_interval.tv_sec = 1; its.it_interval.tv_nsec = 0; // 启动定时器 timer_settime(timer, 0, &its, NULL); // 注册信号处理函数 signal(SIGALRM, timerHandler); // 让主线程休眠一段时间,以便观察定时器是否正常工作 sleep(10); // 销毁定时器 timer_delete(timer); return 0; } ``` 在上面的代码中,我们首先定义了一个信号处理函数 `timerHandler`,其中可以编写定时器触发时要执行的代码。然后,在主函数中创建了一个定时器,设置了定时器的超时时间和间隔时间,并启动了定时器。通过注册信号处理函数,我们将 `timerHandler` 函数与定时器触发的信号 `SIGALRM` 关联起来。最后,让主线程休眠一段时间,以便观察定时器是否正常工作。 当定时器超时时,会触发 `SIGALRM` 信号,进而调用 `timerHandler` 函数。你可以在 `timerHandler` 函数中编写你想要执行的定时任务代码。 请注意,上述代码仅提供了一个基本的定时器实现示例,实际使用中可能需要根据具体需求进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值