0804-----Linux基础----------定时器之 timerfd

1.timerfd 的基本用法

  1.1 timerfd 系列的定时器采用的不是信号,而是 fd 可读,常用的函数有 timerfd_create 、timerfd_settime 和 timerfd_gettime, 这些函数的功能和用法也比较浅显,这里用一个简单的例子(1.2)来说明其用法,create 参数中 CLOCK_REALTIME 是一个相对时间,当系统时间被更改时会进行调整,还有一个参数CLOCK_MONOTONIC,它是绝对时间,更改系统时间对它没有影响,这里flags一般设为0,前面说到,定时器到期表现为 timerfd 可读,因此就可以把该fd加入到IO复用模型当中去(1.3)。

  1.2 创建一个定时器,设置好时间间隔结构体的参数,开启定时器,这样一个定时器就可以工作了,但是这里要注意,timerfd 定时器到期时表现为该 fd 有数据可读,因此一旦到时,一定要把数据 read 出去,不然定时器就无法正常工作。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/timerfd.h>
#define ERR_EXIT(m)     do {         perror(m);        exit(EXIT_FAILURE);    }while(0)
/*
 * 定时器timerfd的基础用法
 */

int main(int argc, const char *argv[])
{
    //创建定时器的fd
    int timerfd = timerfd_create(CLOCK_REALTIME, 0);
    if(timerfd == -1)
        ERR_EXIT("timerfd_create");
    //开启定时器,并设置定时器的时间
    struct itimerspec new_value; // const
    memset(&new_value, 0, sizeof new_value);
    new_value.it_value.tv_sec = 5; //初始到期时间
    new_value.it_interval.tv_sec = 1; //之后的间隔时间
    if(timerfd_settime(timerfd, 0, &new_value, NULL) == -1)
        ERR_EXIT("timerfd_settime");

    char buf[1024] = {0};
    int ret;
    while((ret = read(timerfd, buf, sizeof buf)) > 0){
        printf("ret = %d, read data:%s\n", ret, buf); //
    }

    close(timerfd);
    return 0;
}

  1.3 将timer和poll一起使用,timerfd 加入到 poll 的监听数组中,当 timer 到期,poll 就会监听到该 timerfd。这里 poll 采用的是水平触发模式,也就是说对于某 fd 可读,如果不做 read 处理,那么下次会再次返回该 fd,即该 fd一直可读,等待着被读出去,如果不读出去,就一直被触发,那么定时器就没用了。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <poll.h>
#include <sys/timerfd.h>
#define ERR_EXIT(m)     do {         perror(m);        exit(EXIT_FAILURE);    }while(0)
/*
 * 定时器timerfd 和 epoll 一起使用
 */

int main(int argc, const char *argv[])
{
    //创建定时器的fd
    int timerfd = timerfd_create(CLOCK_REALTIME, 0);
    if(timerfd == -1)
        ERR_EXIT("timerfd_create");
    //开启定时器,并设置定时器的时间
    struct itimerspec new_value; // const
    memset(&new_value, 0, sizeof new_value);
    new_value.it_value.tv_sec = 5; //初始到期时间
    new_value.it_interval.tv_sec = 1; //之后的间隔时间
    if(timerfd_settime(timerfd, 0, &new_value, NULL) == -1)
        ERR_EXIT("timerfd_settime");

    char buf[1024] = {0};
    struct pollfd event[1];
    event[0].fd = timerfd;
    event[0].events = POLLIN;

    while(1){
        int ret =  poll(event, 1, 10000);//等待的最长时间是10s
        if(ret == -1)
            ERR_EXIT("poll");
        else if(ret == 0)
            printf("timeout\n");
        else{
            if(read(timerfd, buf, sizeof buf) == -1) //这里如果不read 会一直被触发
                ERR_EXIT("read");
            printf("foobar....\n");
        }
    }
}

  1.4 一个Timer类,这里把 timerfd 类的函数封装成类,由用户提供定时器到期时要执行的操作(即使用函数回调),这样做的好处,也就是面向对象的好处,对外界提供接口函数,需要时直接用对象调用,更加安全。

#ifndef __TIMER_H__
#define __TIMER_H__

#include "NonCopyable.h"
#include <functional>
#include <sys/timerfd.h>

class Timer : NonCopyable{
    public:
        typedef std::function<void ()> TimerCallback; //定时器回调函数类型
        Timer();
        ~Timer();

        void setTimer(int  init_val, int inter_val); //参数为初始到期时间 和 以后每次的间隔时间
        void setCallback(const TimerCallback &callback);
        void runTimer();

    private:
        int timerfd_;
        struct itimerspec howlong_;
        TimerCallback  callback_; //用户自定义的逻辑
};



#endif  /*__TIMER_H__*/
#include "Timer.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <poll.h>
#include <iostream>
#define ERR_EXIT(m)     do {         perror(m);        exit(EXIT_FAILURE);    }while(0)


Timer::Timer(){
    timerfd_ = timerfd_create(CLOCK_REALTIME, 0);
    if(timerfd_ == -1)
        ERR_EXIT("timer_create");
    memset(&howlong_, 0, sizeof howlong_);
}

Timer::~Timer(){
    close(timerfd_);
}

void Timer:: setTimer(int init_val, int inter_val){ //参数
    howlong_.it_value.tv_sec = init_val;
    howlong_.it_interval.tv_sec = inter_val;
}

void Timer::setCallback(const TimerCallback &callback){
    callback_ = callback;
}

void Timer::runTimer(){
    //开启定时器
    if(timerfd_settime(timerfd_, 0, &howlong_, NULL) == -1)
        ERR_EXIT("timerfd_settime");

    struct pollfd event[1];
    event[0].fd = timerfd_;
    event[0].events = POLLIN;
    char buf[1024];
    int ret;

    while(1){
       ret = poll(event, 1, 1000); //每隔1s 轮询一次
       if(ret == -1)
           ERR_EXIT("poll");
       else if(ret == 0)
           std::cout << "timerout" << std::endl;
       else{
           if(read(timerfd_, buf, sizeof buf)== -1)
               ERR_EXIT("read");
            callback_(); //调用用户逻辑
       }
    }
}



#include "Timer.h"
#include <iostream>
using namespace std;

void func(){
    cout << "hello world" << endl;
}

int main(int argc, const char *argv[])
{
    Timer tm;
    tm.setTimer(3, 1);
    tm.setCallback(func);
    tm.runTimer();
    return 0;
}

2.Timer 和 Thread 类的组合

  2.1 程序编写思路:

    a)把用户逻辑 bind 到 Timer 里面;

    b)把Timer 的 runTimer 方法bind 到 Thread 里面;

    c)也就是说,把 Timer 的操作封装到线程里,执行线程也就是开启定时器。 

  2.2 源程序清单

    a)Thread.h Thread.cpp

#ifndef __THREAD_H__
#define __THREAD_H__
#include "NonCopyable.h"
#include <pthread.h>
#include <functional>

class Thread : NonCopyable{
    public:
        typedef std::function<void ()> ThreadCallback;

        Thread();
        explicit Thread(const ThreadCallback &callback);
        ~Thread();

        void setCallback(const ThreadCallback &callback);
        void start();
        void join();

    private:
        static void *thread_func(void *);

        pthread_t tid_;
        ThreadCallback callback_;
        bool isStarted_;

};

#endif  /*__THREAD_H__*/
#include "Thread.h"
Thread::Thread()
    :tid_(-1),
     isStarted_(false)
{
}

Thread::Thread(const ThreadCallback &callback)
    :tid_(-1),
     isStarted_(false),
     callback_(callback)
{
}

Thread::~Thread(){
    if(isStarted_)
        pthread_detach(tid_);
}

void Thread::setCallback(const ThreadCallback &callback){
    callback_ = callback;
}

void Thread::start(){
    isStarted_ = true;
    pthread_create(&tid_, NULL, thread_func, this);
}

void Thread::join(){
    isStarted_ = false;
    pthread_join(tid_, NULL);
}

void *Thread::thread_func(void *arg){
    Thread *pt = static_cast<Thread *>(arg);
    pt->callback_();
    return NULL;
}

 

    b) test_timer.cpp

#include "Timer.h"
#include "Thread.h"
#include <iostream>
using namespace std;
/*
 * 使用类的组合 Thread 和 Timer 类
 */
class TimerThread{
    public:
        TimerThread();
        void print(); //定时器到期时 执行的函数
        void startTimerThread();
    private:
        Thread thread_;
        Timer timer_;
};

TimerThread::TimerThread(){}

void TimerThread::print(){
    cout << "hello world" << endl;
}

void TimerThread::startTimerThread(){
    timer_.setTimer(3, 1);
    timer_.setCallback(bind(&TimerThread::print, this));

    // 线程类用来封装Timer的操作
    thread_.setCallback(bind(&Timer::runTimer, &timer_));
    thread_.start();
    thread_.join();
}

int main(int argc, const char *argv[])
{
    TimerThread tt;
    tt.startTimerThread();
    return 0;
}

 

  

 

0804-----Linux基础----------定时器之 timerfd,古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。