程序简介:
1.把timerfd和epoll的功能封装成一个类,timerfd负责创建计时器,而epoll负责等待timer超时,然后调用用户设定得回调函数。
2.至于timerfd的基本功能不明白,就参考这位大神的技术文章:blog.youkuaiyun.com/chgaowei/article/details/21295811
3.至于epoll的基本功能不明白,就参考这位大神得技术文章:blog.youkuaiyun.com/xiajun07061225/article/details/9250579
Timer.h
#ifndef __TIMER_H_
#define __TIMER_H_
/*
* Name: Timer
* Date: 10-12-2015
* Author: Sumkee
* Brief: It's general timer that provides a friendly interfaces
* to create the timer
*
*/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <unistd.h>
#include <sys/timerfd.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <stdint.h>
#include <pthread.h>
#include <iostream>
#include <map>
#include <algorithm>
#include <list>
using namespace std;
class Timer {
public:
Timer();
~Timer();
// The structure of timer event
typedef void (*CALLBACK_FN)(void *);
typedef struct _TimerEvent {
int fd;
CALLBACK_FN cbf;
void *args;
} TimerEvent;
/*
* Name: start
* Brief: start the timer
* @interval: The interval, the unit is ms
* @cbf: The callback function
* @args: The arguments of callback function
* @triggered_on_start: Determine tirggered on start or not
*
*/
bool start(const uint interval, CALLBACK_FN cbf,
void *args,const bool triggered_on_start=false);
/*
* Name: stop
* Brief: stop the timer
*
*/
void stop();
private:
bool m_is_start;
TimerEvent m_te;
};
#endif
Timer.cpp
#include "timer.h"
/*
* Save the global data such as file descriptors of timerfd and
* create a new thread for epoll
*
*/
class TimerPrivate {
public:
TimerPrivate();
~TimerPrivate() {
pthread_mutex_destroy(&m_mutex);
}
// Some constant
enum {
MaxEPOLLSize = 20000,
};
/*
* Name: epoll_proc
* Brief: this function run on new thread for epoll
*
*/
static void* epoll_proc(void *);
/*
* Get the timer event by fd
*
*/
static Timer::TimerEvent get_timer_event(int fd);
/*
* Add the timer event to map and epoll
*
*/
static bool add_timer_event(const Timer::TimerEvent &te);
/*
* Remove the timer event from map adn epoll by fd
*
*/
static void remove_timer_event(const int fd);
// Map of file descriptor
int m_epoll_fd;
typedef map<int, Timer::TimerEvent> MapTimerEvent;
MapTimerEvent m_map_te;
pthread_t m_tid;
pthread_mutex_t m_mutex;
};
// The declare of TimerPrivate
static TimerPrivate g_tp;
TimerPrivate::TimerPrivate() {
try {
// Initialization
// Init mutex
int res = pthread_mutex_init(&m_mutex, 0);
if(res == -1) {
perror("pthread_mutex_init");
throw;
}
// Create epoll
m_epoll_fd = epoll_create(MaxEPOLLSize);
if(m_epoll_fd == -1) {
perror("epoll_create");
throw;
}
// Create thread for epoll
res = pthread_create(&m_tid, 0, TimerPrivate::epoll_proc, 0);
if(res == -1) {
perror("pthread_create");
throw;
}
} catch (...) {}
}
void* TimerPrivate::epoll_proc(void *) {
struct epoll_event events[MaxEPOLLSize];
while(1) {
// Wait for notice
int n =epoll_wait(g_tp.m_epoll_fd, events, MaxEPOLLSize, -1);
pthread_mutex_lock(&g_tp.m_mutex);
for(int i=0; i<n; ++i) {
int fd = events[i].data.fd;
// Clear buffer
uint64_t buf;
read(fd, &buf, sizeof(uint64_t));
// Call the callback function when timer expiration
Timer::TimerEvent te = TimerPrivate::get_timer_event(events[i].data.fd);
if(te.cbf) {
te.cbf(te.args);
}
}
pthread_mutex_unlock(&g_tp.m_mutex);
}
return 0;
}
Timer::TimerEvent TimerPrivate::get_timer_event(int fd) {
return g_tp.m_map_te[fd];
}
bool TimerPrivate::add_timer_event(const Timer::TimerEvent &te) {
// Add timer event for epoll
struct epoll_event epe;
epe.data.fd = te.fd;
epe.events = EPOLLIN | EPOLLET;
int res = epoll_ctl(g_tp.m_epoll_fd, EPOLL_CTL_ADD, te.fd, &epe);
if(res == -1) {
perror("epoll_ctl");
return false;
}
// Insert timer event to map
g_tp.m_map_te[te.fd] = te;
return true;
}
void TimerPrivate::remove_timer_event(const int fd) {
// Remove from epoll
int res = epoll_ctl(g_tp.m_epoll_fd, EPOLL_CTL_DEL, fd,0);
if(res == -1) {
perror("epoll_ctl");
return;
}
// Remove from map
MapTimerEvent::iterator iter = g_tp.m_map_te.find(fd);
g_tp.m_map_te.erase(iter);
}
Timer::Timer() : m_is_start(false) {
::memset(&m_te, 0, sizeof(TimerEvent));
}
Timer::~Timer() {
if(m_is_start) {
stop();
m_is_start = false;
}
}
bool Timer::start(const uint interval, CALLBACK_FN cbf, void *args, const bool triggered_on_start) {
pthread_mutex_lock(&g_tp.m_mutex);
if(!m_is_start) {
if(!cbf) {
cout << "start:" << "callback function can't set to be null" << endl;
return false;
}
// Create timer
struct itimerspec timer;
double dfsec = (double)interval/1000;
uint32_t sec=dfsec;
uint64_t number_ns = 1000000000;
uint64_t nsec = dfsec>=1 ? fmod(dfsec,(int)dfsec)*number_ns : dfsec*number_ns;
timer.it_value.tv_nsec = triggered_on_start ? 0 : nsec;
timer.it_value.tv_sec = triggered_on_start ? 0 : sec;
timer.it_interval.tv_nsec = nsec;
timer.it_interval.tv_sec = sec;
int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
if(fd == -1) {
perror("timerfd_create");
return false;
}
int res = timerfd_settime(fd, 0, &timer, 0);
if(res == -1) {
perror("timerfd_settime");
return false;
}
// Add timer for epoll
TimerEvent te;
te.fd = fd;
te.cbf = cbf;
te.args = args;
res = TimerPrivate::add_timer_event(te);
if(res == false) {
return false;
}
// Change the attributes of class
m_te = te;
m_is_start = true;
} else {
cout << "start:Timer already start" << endl;
return false;
}
pthread_mutex_unlock(&g_tp.m_mutex);
return true;
}
void Timer::stop() {
pthread_mutex_lock(&g_tp.m_mutex);
// Remove from map and epoll
TimerPrivate::remove_timer_event(m_te.fd);
// Close the timer
int res = close(m_te.fd);
if(res == -1) {
perror("close");
}
// Clear the attributes of class
m_is_start = false;
pthread_mutex_unlock(&g_tp.m_mutex);
}
/**************************************************************************/
// Test
void timer_proc(void *args) {
cout << args << endl;
}
int main() {
list<Timer*> l;
for(int i=0; i<10;++i) {
Timer *t = new Timer();
t->start(500, timer_proc, reinterpret_cast<void*>(i));
l.push_back(t);
}
sleep(3);
return 0;
}