spring 定时器设置停止_定时器之timerfd

前言

服务端遇到定时任务是很常见的,主要包括两类:once和repeat。常见的方案就是使用时间堆或时间片+I/O复用,今天给大家介绍一个更方便的方法:timerfd_xx。

接口说明
123456789
#include        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
12345678
int timerfd_create(int clockid, int flags);/*     * timerfd_create() 函数创建一个定时器对象,同时返回一个与之关联的文件描述符。     * clockid:clockid标识指定的时钟计数器,可选值(CLOCK_REALTIME、CLOCK_MONOTONIC。。。)     * CLOCK_REALTIME:系统实时时间,随系统实时时间改变而改变,即从UTC1970-1-1 0:0:0开始计时,中间时刻如果系统时间被用户改成其他,则对应的时间相应改变     * CLOCK_MONOTONIC:从系统启动这一刻起开始计时,不受系统时间被用户改变的影响     * flags:参数flags(TFD_NONBLOCK(非阻塞模式)/TFD_CLOEXEC(表示当程序执行exec函数时本fd将被系统自动关闭,表示不传递)     */
timerfd_settime
1234567891011121314
 int timerfd_settime(int fd, int flags,                           const struct itimerspec *new_value,                           struct itimerspec *old_value);/*     * timerfd_settime()此函数用于设置新的超时时间,并开始计时,能够启动和停止定时器;     * fd: 参数fd是timerfd_create函数返回的文件句柄     * flags:参数flags为1代表设置的是绝对时间(TFD_TIMER_ABSTIME 表示绝对定时器);为0代表相对时间。     * new_value: 参数new_value指定定时器的超时时间以及超时间隔时间     * old_value: 如果old_value不为NULL, old_vlaue返回之前定时器设置的超时时间,具体参考timerfd_gettime()函数     *     * ** it_interval不为0则表示是周期性定时器。     *    it_value和it_interval都为0表示停止定时器     */

其中itimerspec结构如下:

1234567891011
/*     * struct timespec {     *     time_t tv_sec; //秒     *     long tv_nsec; //纳秒     * };     *     * struct itimerspec {     *     struct timespec it_interval;  //Interval for periodic timer (定时间隔周期)     *     struct timespec it_value;     //Initial expiration (第一次超时时间)     * };     */
timerfd_gettime
12
int timerfd_gettime(int fd, struct itimerspec *curr_value);/*此函数用于获得定时器距离下次超时还剩下的时间。如果调用时定时器已经到期,并且该定时器处于循环模式(设置超时时间时struct itimerspec::it_interval不为0),那么调用此函数之后定时器重新开始计时*/
使用说明
Timer类
1234567891011121314151617
#ifndef _TIMER_H__#define _TIMER_H__class Timer{public:    int initAlarm(unsigned long long n_second, unsigned long long n_nanoseconds);    int setAlarm(unsigned long long n_second, unsigned long long n_nanoseconds);    unsigned long long waitAlarm();    Timer();    ~Timer();private:    int m_timerFd;};#endif // !_TIMER_H__

Timer.cpp实现

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
#include "Timer.h"#include #include Timer::Timer(){m_timerFd=-1;}Timer::~Timer(){    if(m_timerFd!=-1){        close(m_timerFd);        m_timerFd=-1;    }}int Timer::initAlarm(unsigned long long  n_second, unsigned long long n_nanoseconds){       /*     * 创建一个定时器对象     */    /*     * timerfd_create() 函数创建一个定时器对象,同时返回一个与之关联的文件描述符。     * clockid:clockid标识指定的时钟计数器,可选值(CLOCK_REALTIME、CLOCK_MONOTONIC。。。)     * CLOCK_REALTIME:系统实时时间,随系统实时时间改变而改变,即从UTC1970-1-1 0:0:0开始计时,中间时刻如果系统时间被用户改成其他,则对应的时间相应改变     * CLOCK_MONOTONIC:从系统启动这一刻起开始计时,不受系统时间被用户改变的影响     * flags:参数flags(TFD_NONBLOCK(非阻塞模式)/TFD_CLOEXEC(表示当程序执行exec函数时本fd将被系统自动关闭,表示不传递)     */    m_timerFd = timerfd_create(CLOCK_MONOTONIC, 0);    if(m_timerFd==-1){        return -1;    }    /*     * 设置定时器时间     */    /*     * struct timespec {     *     time_t tv_sec; //秒     *     long tv_nsec; //纳秒     * };     *     * struct itimerspec {     *     struct timespec it_interval;  //Interval for periodic timer (定时间隔周期)     *     struct timespec it_value;     //Initial expiration (第一次超时时间)     * };     */    struct itimerspec new_value;    new_value.it_value.tv_sec = n_second;    new_value.it_value.tv_nsec = n_nanoseconds;    new_value.it_interval.tv_sec = n_second;    new_value.it_interval.tv_nsec = n_nanoseconds;    /*     * timerfd_settime()此函数用于设置新的超时时间,并开始计时,能够启动和停止定时器;     * fd: 参数fd是timerfd_create函数返回的文件句柄     * flags:参数flags为1代表设置的是绝对时间(TFD_TIMER_ABSTIME 表示绝对定时器);为0代表相对时间。     * new_value: 参数new_value指定定时器的超时时间以及超时间隔时间     * old_value: 如果old_value不为NULL, old_vlaue返回之前定时器设置的超时时间,具体参考timerfd_gettime()函数     *     * ** it_interval不为0则表示是周期性定时器。     *    it_value和it_interval都为0表示停止定时器     */    return timerfd_settime(m_timerFd, 0, &new_value, NULL);    }int Timer::setAlarm(unsigned long long  n_second, unsigned long long n_nanoseconds){    struct itimerspec new_value;    new_value.it_value.tv_sec = n_second;    new_value.it_value.tv_nsec = n_nanoseconds;    new_value.it_interval.tv_sec = n_second;    new_value.it_interval.tv_nsec = n_nanoseconds;    return timerfd_settime(m_timerFd, 0, &new_value, NULL);     }unsigned long long Timer::waitAlarm(){    unsigned long long tmp_exp = 0;    read(m_timerFd, &tmp_exp, sizeof(tmp_exp));    return tmp_exp;}
使用方法
  1. 可以单独使用

    1234567
    Timer timer;   timer.initAlarm(ServerDefaultSetting::kDuccUpdateInterval, 0);   DuccServer duccServer;   while (!isStop())   {       timer.waitAlarm();   }
  2. 结合IO复用

1
<span  color="red">将timer_create创建的fd加入即可,需要注意的是要读取fd上的超时时间,否则可能会一直触发IO可读。span>
优缺点
  1. 优点

  • timerfd_create 把时间变成了一个文件描述符,该“文件”在定时器超时的那一刻变得可读,这样就能很方便地融入到 select/poll 框架中,用统一的方式来处理 IO 事件和超时事件。

  • 利用select, poll的timeout实现定时功能,它们的缺点是定时精度只有毫秒,远低于 timerfd_settime 的定时精度。

  1. 缺点

  • 在于IO复用一起使用的时,需要注意超时之后需要read一下,否则可能会一直触发。

  • 注意os的版本(centos5可能不支持,一般是支持的)

f55d711a441b3a0d147973d73a2198be.gif

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值