epoll定时器实现系列文章:linux c++ 利用timerfd和epoll封装计时器(Timer)类

589 阅读3分钟

blog.csdn.net/sumkee911/a…

程序简介:

1.把timerfd和epoll的功能封装成一个类,timerfd负责创建计时器,而epoll负责等待timer超时,然后调用用户设定得回调函数。

2.至于timerfd的基本功能不明白,就参考这位大神的技术文章:blog.csdn.net/oxp7085915/…

3.至于epoll的基本功能不明白,就参考这位大神得技术文章:www.cnblogs.com/Anker/p/326…

\

Timer.h

[cpp]  view plain  copy

  1. #ifndef __TIMER_H_  
  2. #define __TIMER_H_  
  3.   
  4. /* 
  5.  *  Name: Timer 
  6.  *  Date: 10-12-2015  
  7.  *  Author: Sumkee 
  8.  *  Brief: It's general timer that provides a friendly interfaces 
  9.  *         to create the timer 
  10.  * 
  11.  */  
  12.   
  13. #include <cstdio>  
  14. #include <cstdlib>  
  15. #include <cstring>  
  16. #include <cmath>  
  17. #include <unistd.h>  
  18. #include <sys/timerfd.h>  
  19. #include <sys/epoll.h>  
  20. #include <sys/types.h>  
  21. #include <stdint.h>  
  22. #include <pthread.h>  
  23. #include <iostream>  
  24. #include <map>  
  25. #include <algorithm>  
  26. #include <list>  
  27.   
  28. using namespace std;  
  29.   
  30.   
  31. class Timer {  
  32. public:  
  33.     Timer();  
  34.     ~Timer();  
  35.       
  36.     // The structure of timer event  
  37.     typedef void (*CALLBACK_FN)(void *);  
  38.     typedef struct _TimerEvent {  
  39.         int fd;  
  40.         CALLBACK_FN cbf;  
  41.         void *args;  
  42.     } TimerEvent;  
  43.   
  44.     /* 
  45.      *  Name: start 
  46.      *  Brief: start the timer 
  47.      *  @interval: The interval, the unit is ms 
  48.      *  @cbf: The callback function 
  49.      *  @args: The arguments of callback function 
  50.      *  @triggered_on_start: Determine tirggered on start or not 
  51.      * 
  52.      */   
  53.     bool start(const uint interval, CALLBACK_FN cbf,  
  54.             void *args,const bool triggered_on_start=false);  
  55.   
  56.     /* 
  57.      *  Name: stop 
  58.      *  Brief: stop the timer 
  59.      * 
  60.      */  
  61.     void stop();  
  62.   
  63. private:  
  64.     bool m_is_start;  
  65.     TimerEvent m_te;  
  66. };  
  67.   
  68. #endif  

Timer.cpp

[cpp]  view plain  copy

  1. #include "timer.h"  
  2.   
  3. /* 
  4.  * Save the global data such as file descriptors of timerfd and  
  5.  * create a new thread for epoll 
  6.  * 
  7.  */  
  8. class TimerPrivate {  
  9.     public:  
  10.         TimerPrivate();  
  11.         ~TimerPrivate() {  
  12.             pthread_mutex_destroy(&m_mutex);  
  13.         }  
  14.   
  15.         // Some constant  
  16.         enum {  
  17.             MaxEPOLLSize = 20000,      
  18.         };  
  19.   
  20.         /* 
  21.          *  Name: epoll_proc 
  22.          *  Brief: this function run on new thread for epoll 
  23.          * 
  24.          */  
  25.         static void* epoll_proc(void *);  
  26.   
  27.         /* 
  28.          *  Get the timer event by fd 
  29.          * 
  30.          */  
  31.         static Timer::TimerEvent get_timer_event(int fd);  
  32.   
  33.         /* 
  34.          *  Add the timer event to map and epoll 
  35.          * 
  36.          */   
  37.         static bool add_timer_event(const Timer::TimerEvent &te);   
  38.   
  39.         /* 
  40.          *  Remove the timer event from map adn epoll by fd 
  41.          * 
  42.          */  
  43.         static void remove_timer_event(const int fd);  
  44.   
  45.         // Map of file descriptor  
  46.         int m_epoll_fd;  
  47.         typedef map<int, Timer::TimerEvent> MapTimerEvent;  
  48.         MapTimerEvent m_map_te;  
  49.         pthread_t m_tid;  
  50.         pthread_mutex_t m_mutex;   
  51. };  
  52.   
  53. // The declare of TimerPrivate  
  54. static TimerPrivate g_tp;  
  55.   
  56. TimerPrivate::TimerPrivate() {  
  57.     try {  
  58.         // Initialization  
  59.         // Init mutex  
  60.         int res = pthread_mutex_init(&m_mutex, 0);  
  61.         if(res == -1) {  
  62.             perror("pthread_mutex_init");  
  63.             throw;  
  64.         }  
  65.   
  66.         // Create epoll  
  67.         m_epoll_fd = epoll_create(MaxEPOLLSize);  
  68.         if(m_epoll_fd == -1) {  
  69.             perror("epoll_create");  
  70.             throw;  
  71.         }  
  72.   
  73.         // Create thread for epoll  
  74.         res = pthread_create(&m_tid, 0, TimerPrivate::epoll_proc, 0);  
  75.         if(res == -1) {  
  76.             perror("pthread_create");  
  77.             throw;  
  78.         }  
  79.     } catch (...) {}   
  80. }  
  81.   
  82. void* TimerPrivate::epoll_proc(void *) {  
  83.     struct epoll_event events[MaxEPOLLSize];  
  84.     while(1) {  
  85.         // Wait for notice  
  86.         int n =epoll_wait(g_tp.m_epoll_fd, events, MaxEPOLLSize, -1);   
  87.         pthread_mutex_lock(&g_tp.m_mutex);  
  88.         for(int i=0; i<n; ++i) {  
  89.             int fd = events[i].data.fd;  
  90.             // Clear buffer  
  91.             uint64_t buf;  
  92.             read(fd, &buf, sizeof(uint64_t));  
  93.   
  94.             // Call the callback function when timer expiration  
  95.             Timer::TimerEvent te = TimerPrivate::get_timer_event(events[i].data.fd);  
  96.             if(te.cbf) {  
  97.                 te.cbf(te.args);  
  98.             }  
  99.         }  
  100.         pthread_mutex_unlock(&g_tp.m_mutex);  
  101.     }  
  102.     return 0;  
  103. }  
  104.   
  105. Timer::TimerEvent TimerPrivate::get_timer_event(int fd) {  
  106.     return g_tp.m_map_te[fd];  
  107. }  
  108.   
  109. bool TimerPrivate::add_timer_event(const Timer::TimerEvent &te) {  
  110.     // Add timer event for epoll  
  111.     struct epoll_event epe;  
  112.     epe.data.fd = te.fd;  
  113.     epe.events = EPOLLIN | EPOLLET;  
  114.     int res = epoll_ctl(g_tp.m_epoll_fd, EPOLL_CTL_ADD, te.fd, &epe);   
  115.     if(res == -1) {  
  116.         perror("epoll_ctl");  
  117.         return false;  
  118.     }  
  119.   
  120.     // Insert timer event to map  
  121.     g_tp.m_map_te[te.fd] = te;  
  122.   
  123.     return true;  
  124. }  
  125.   
  126. void TimerPrivate::remove_timer_event(const int fd) {  
  127.     // Remove from epoll  
  128.     int res = epoll_ctl(g_tp.m_epoll_fd, EPOLL_CTL_DEL, fd,0);  
  129.     if(res == -1) {  
  130.         perror("epoll_ctl");  
  131.         return;   
  132.     }  
  133.   
  134.     // Remove from map  
  135.     MapTimerEvent::iterator iter = g_tp.m_map_te.find(fd);  
  136.     g_tp.m_map_te.erase(iter);  
  137. }  
  138.   
  139. Timer::Timer() : m_is_start(false) {  
  140.     ::memset(&m_te, 0, sizeof(TimerEvent));  
  141. }  
  142.   
  143. Timer::~Timer() {  
  144.     if(m_is_start) {  
  145.         stop();  
  146.         m_is_start = false;  
  147.     }  
  148. }  
  149.   
  150. bool Timer::start(const uint interval, CALLBACK_FN cbf, void *args, const bool triggered_on_start) {  
  151.     pthread_mutex_lock(&g_tp.m_mutex);  
  152.   
  153.     if(!m_is_start) {  
  154.         if(!cbf) {  
  155.             cout << "start:" << "callback function can't set to be null" << endl;  
  156.             return false;  
  157.         }  
  158.   
  159.         // Create timer  
  160.         struct itimerspec timer;  
  161.         double dfsec = (double)interval/1000;  
  162.         uint32_t sec=dfsec;  
  163.         uint64_t number_ns = 1000000000;  
  164.         uint64_t nsec = dfsec>=1 ? fmod(dfsec,(int)dfsec)*number_ns : dfsec*number_ns;  
  165.         timer.it_value.tv_nsec = triggered_on_start ? 0 : nsec;  
  166.         timer.it_value.tv_sec = triggered_on_start ? 0 : sec;  
  167.         timer.it_interval.tv_nsec = nsec;  
  168.         timer.it_interval.tv_sec = sec;  
  169.   
  170.         int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);  
  171.         if(fd == -1) {  
  172.             perror("timerfd_create");  
  173.             return false;  
  174.         }  
  175.   
  176.         int res = timerfd_settime(fd, 0, &timer, 0);  
  177.         if(res == -1) {  
  178.             perror("timerfd_settime");  
  179.             return false;  
  180.         }  
  181.   
  182.         // Add timer for epoll  
  183.         TimerEvent te;  
  184.         te.fd = fd;  
  185.         te.cbf = cbf;  
  186.         te.args = args;  
  187.         res = TimerPrivate::add_timer_event(te);  
  188.         if(res == false) {  
  189.             return false;  
  190.         }  
  191.   
  192.         // Change the attributes of class  
  193.         m_te = te;  
  194.         m_is_start = true;  
  195.     } else {  
  196.         cout << "start:Timer already start" << endl;  
  197.         return false;  
  198.     }  
  199.   
  200.     pthread_mutex_unlock(&g_tp.m_mutex);  
  201.     return true;  
  202. }  
  203.   
  204. void Timer::stop() {  
  205.     pthread_mutex_lock(&g_tp.m_mutex);  
  206.   
  207.     // Remove from map and epoll  
  208.     TimerPrivate::remove_timer_event(m_te.fd);  
  209.   
  210.     // Close the timer  
  211.     int res = close(m_te.fd);  
  212.     if(res == -1) {  
  213.         perror("close");  
  214.     }  
  215.   
  216.     // Clear the attributes of class  
  217.     m_is_start = false;  
  218.   
  219.     pthread_mutex_unlock(&g_tp.m_mutex);  
  220. }  
  221.   
  222. /**************************************************************************/  
  223. // Test  
  224. void timer_proc(void *args) {  
  225.     cout << args << endl;  
  226. }  
  227.   
  228. int main() {  
  229.     list<Timer*> l;  
  230.     for(int i=0; i<10;++i) {  
  231.         Timer *t = new Timer();  
  232.         t->start(500, timer_proc, reinterpret_cast<void*>(i));  
  233.         l.push_back(t);  
  234.     }  
  235.     sleep(3);  
  236.     return 0;  
  237. }  

\