以下代码来源:http://www.pudn.com/downloads165/sourcecode/unix_linux/detail756768.html
#ifndef TIMER_MANAGER_H #define TIMER_MANAGER_H #include <map> #include <time.h> #define SIGMYTIMER (SIGRTMAX) class ITimer; class TimerCache; class TimerManager { typedef std::map<timer_t , int> TimerIdMap; public: TimerManager(); virtual ~TimerManager(); int initialize(TimerCache * pCache); // create and start the timer timer_t createTimer(ITimer * timer , int interval , bool periodical = false , void * args = 0); // cancel the timer. int deleteTimer(timer_t timerId); protected: // the pointer to the timer cache. TimerCache * pCache_m; // timer id map <timer_t to int> TimerIdMap idMap_m; }; #endif
#include "TimerManager.h" #include "TimerCache.h" #include "TimerHandler.h" #include "oamTask.h" #include <time.h> #include <signal.h> #include <pthread.h> #include <unistd.h> #include <stdio.h> static void Timeout(int signo, siginfo_t* info, void* context) { int endTime = time(0); CommonData data; data.setData((char *)&endTime); data.setLength(sizeof(int)); TimerHandler::instance()->putq(data); } TimerManager::TimerManager():pCache_m(0) {} TimerManager::~TimerManager() { idMap_m.clear(); } int TimerManager::initialize(TimerCache * pCache) { pCache_m = pCache; struct sigaction sysact; sigemptyset(&sysact.sa_mask); sysact.sa_flags = SA_SIGINFO; sysact.sa_sigaction = Timeout; return sigaction(SIGMYTIMER, &sysact, 0); } timer_t TimerManager::createTimer(ITimer * timer , int interval , bool periodical, void * args) { int currentTime = time(0); int timerId = pCache_m->insert(timer , currentTime , interval , periodical , args); struct sigevent evp; timer_t nTimerID; evp.sigev_notify = SIGEV_SIGNAL; evp.sigev_signo = SIGMYTIMER; evp.sigev_value.sival_ptr = &nTimerID; int nCreate = timer_create(CLOCK_REALTIME, &evp, &nTimerID); if (nCreate == 0) { struct itimerspec value; struct itimerspec ovalue; value.it_value.tv_sec = interval; value.it_value.tv_nsec = 0; if (periodical) { value.it_interval.tv_sec = value.it_value.tv_sec; value.it_interval.tv_nsec = value.it_value.tv_nsec; } else { value.it_interval.tv_sec = 0; value.it_interval.tv_nsec = 0; } timer_settime(nTimerID, 0, &value, &ovalue); } else { perror("create timer failed."); return (timer_t)-1; } idMap_m[nTimerID] = timerId; return nTimerID; } int TimerManager::deleteTimer(timer_t timerId) { int ret = timer_delete(timerId); if (ret == -1) { perror("delete timer failed."); return -1; } ret = pCache_m->remove(idMap_m[timerId]); if (ret == -1) { perror("remove the timer from the cache failed."); return -1; } TimerIdMap::iterator it = idMap_m.find(timerId); if (it != idMap_m.end()) { idMap_m.erase(it); } else { perror("can not find the timerId from the id map."); return -1; } return 0; }
TimerHandler.h
#ifndef _TIMER_HANDLER_H #define _TIMER_HANDLER_H #include "oamTask.h" class TimerCache; class TimerHandler:public OamTask { public: TimerHandler(); virtual ~TimerHandler(); int initialize(TimerCache * pCache); static TimerHandler * instance(); protected: int handle(CommonData * data); TimerCache * pCache_m; static TimerHandler * instance_m; }; #endif
TimerHandler.cc
#include "TimerHandler.h" #include "TimerCache.h" #include "TimerManager.h" #include <stdio.h> TimerHandler * TimerHandler::instance_m = 0; TimerHandler * TimerHandler::instance() { if (instance_m == 0) { instance_m = new TimerHandler; } return instance_m; } int TimerHandler::handle(CommonData * data) { if (data->getData()) { int currentTime = *((int *)data->getData()); pCache_m->handleTimeout(currentTime); } return 0; } int TimerHandler::initialize(TimerCache * pCache) { pCache_m = pCache; sigset_t mask; sigemptyset(&mask); sigaddset(&mask , SIGMYTIMER); int ret = OamTask::initialize(mask); if (ret == -1) { perror("task initializing failed."); return -1; } return start(); } TimerHandler::TimerHandler():pCache_m(0) {} TimerHandler::~TimerHandler() {}
TimerCache.h
#ifndef _TIMER_CACHE_H #define _TIMER_CACHE_H #include <pthread.h> class ITimer; // timer node. typedef struct tag_Timer { struct tag_Timer * next; // common interface for the client application. ITimer * timer; // the identity id for the timer. int timerId; // false: this is not a periodical timer. // true: this is a periodical timer. bool isPeriodical; // the start time of the timer. int startTime; // the timeout for the timer (second). int interval; // when the timer timeouts, this argument will be with // the timeout callback function. void * args; tag_Timer() { timer = 0; timerId = -1; next = 0; isPeriodical = false; startTime = -1; interval = -1; args = 0; } }Timer; // timer array. typedef struct tag_TimerList { Timer * nextTimer; tag_TimerList() { nextTimer = 0; } }TimerList; class TimerCache { public: TimerCache(); virtual ~TimerCache(); // insert a timer into the hash table. int insert(ITimer * timer , int currentTime , int interval , bool isPeriodical = false , void * args = 0); // remove the timer from the hash table with the timer id. int remove(int timerId); // when the timer is expired, this function will be called. void handleTimeout(int currentTime); private: // the granularity of the hash table. static const int LIST_CAPACITY = 50; // the timer array. TimerList timerList_m[LIST_CAPACITY]; // the lock for the cache accessing. pthread_mutex_t mutex_m; // if the timer is periodical, after timeout, the timer will be re-inserted into the // hash table. void reInsert(Timer * timer , int currentTime); // reclaim the hash table. void destroyAll(); // get the timer id int getTimerId(); // when the timer is expired, this function will be called. void expire(int currentTime); }; #endif
TimerCache.cc
#include "TimerCache.h" #include "ITimer.h" #include <time.h> #include <stdio.h> static int const ERROR_SCOPE = 5; TimerCache::TimerCache() { pthread_mutex_init(&mutex_m , 0); } TimerCache::~TimerCache() { destroyAll(); pthread_mutex_destroy(&mutex_m); } int TimerCache::insert(ITimer * timer , int currentTime , int interval , bool isPeriodical , void * args) { pthread_mutex_lock(&mutex_m); Timer * pTimer = new Timer; pTimer->timer = timer; pTimer->timerId = getTimerId(); pTimer->isPeriodical = isPeriodical; pTimer->interval = interval; pTimer->startTime = currentTime; pTimer->args = args; int endTime = currentTime + interval; int index = endTime % LIST_CAPACITY; if (timerList_m[index].nextTimer) { Timer * tmpTimer = timerList_m[index].nextTimer; Timer * prevTimer = tmpTimer; while (tmpTimer) { int tmpEndTime = tmpTimer->interval + tmpTimer->startTime; if (tmpEndTime < endTime) { prevTimer = tmpTimer; tmpTimer = tmpTimer->next; } else { pTimer->next = prevTimer->next; prevTimer->next = pTimer; break; } } } else { timerList_m[index].nextTimer = pTimer; } int timerId = pTimer->timerId; pthread_mutex_unlock(&mutex_m); return timerId; } int TimerCache::getTimerId() { static int timerId = 0; if (timerId < 0x80000000) { timerId ++; } else { timerId = 0; } return timerId; } void TimerCache::destroyAll() { pthread_mutex_lock(&mutex_m); for (int i = 0;i < LIST_CAPACITY;i++) { Timer * pTimer = timerList_m[i].nextTimer; while (pTimer) { Timer * tmpTimer = pTimer; pTimer = pTimer->next; delete tmpTimer; tmpTimer = 0; } } pthread_mutex_unlock(&mutex_m); } void TimerCache::expire(int currentTime) { pthread_mutex_lock(&mutex_m); int index = currentTime % LIST_CAPACITY; Timer * pTimer = timerList_m[index].nextTimer; while (pTimer) { int endTime = pTimer->interval + pTimer->startTime; timerList_m[index].nextTimer = pTimer->next; if (endTime <= currentTime) { pTimer->timer->timeout(pTimer->timerId , pTimer->args); if (pTimer->isPeriodical) { pTimer->startTime = currentTime; reInsert(pTimer, currentTime); } delete pTimer; pTimer = timerList_m[index].nextTimer; } else { break; } } pthread_mutex_unlock(&mutex_m); } void TimerCache::reInsert(Timer * timer , int currentTime) { Timer * pTimer = new Timer; pTimer->timer = timer->timer; pTimer->timerId = timer->timerId; pTimer->isPeriodical = timer->isPeriodical; pTimer->interval = timer->interval; pTimer->startTime = currentTime; pTimer->args = timer->args; int endTime = currentTime + timer->interval; int index = endTime % LIST_CAPACITY; if (timerList_m[index].nextTimer) { Timer * tmpTimer = timerList_m[index].nextTimer; Timer * prevTimer = tmpTimer; while (tmpTimer) { int tmpEndTime = tmpTimer->interval + tmpTimer->startTime; if (tmpEndTime < endTime) { prevTimer = tmpTimer; tmpTimer = tmpTimer->next; } else { pTimer->next = prevTimer->next; prevTimer->next = pTimer; break; } } } else { timerList_m[index].nextTimer = pTimer; } return; } void TimerCache::handleTimeout(int currentTime) { for (int i = 0;i < ERROR_SCOPE;i ++) { expire(currentTime - i); } } int TimerCache::remove(int timerId) { pthread_mutex_lock(&mutex_m); for (int i = 0;i < LIST_CAPACITY; i++) { Timer * pTimer = timerList_m[i].nextTimer; Timer * prev = pTimer; while (pTimer) { if (pTimer->timerId == timerId) { prev->next = pTimer->next; delete pTimer; pTimer = 0; pthread_mutex_unlock(&mutex_m); return 0; } prev = pTimer; pTimer = pTimer->next; } } pthread_mutex_unlock(&mutex_m); return -1; }
oamTask.h
#ifndef OAMTASK_H_ #define OAMTASK_H_ #include "oamRunner.h" #include <signal.h> class CommonData { public: CommonData(); CommonData(char * rawData , int length); virtual ~CommonData(); int getLength() const; void setLength(int length); char * getData() const; void setData(char * rawData); private: // the length of the raw data int length_m; // the pointer of the raw data char * rawData_m; }; class OamTask:public OamRunner { public: OamTask(); virtual ~OamTask(); int initialize(sigset_t mask); int putq(CommonData & commonData); int getq(CommonData & commonData); protected: // the logic handler which is implemented by the derived-class virtual int handle(CommonData * pData); private: // the definition pf the pipe type. enum { FD_READ = 0, FD_WRITE, FD_MAX }; // the thread method. virtual int run(); // the FD of the queue. int queue_m[FD_MAX]; // signal set sigset_t mask_m; }; #endif
oamTask.cc
#include "oamTask.h" #include <signal.h> #include <unistd.h> #include <string.h> #include <stdio.h> #include <errno.h> CommonData::CommonData():length_m(0) , rawData_m(0) {} CommonData::CommonData(char * rawData , int length) :length_m(length) , rawData_m(rawData) {} CommonData::~CommonData() { rawData_m = 0; length_m = 0; } int CommonData::getLength() const { return length_m; } void CommonData::setLength(int length) { length_m = length; } char * CommonData::getData() const { return rawData_m; } void CommonData::setData(char * rawData) { rawData_m = rawData; } OamTask::OamTask() { queue_m[FD_READ] = -1; queue_m[FD_WRITE] = -1; } OamTask::~OamTask() { if (queue_m[FD_READ] != -1) { close(queue_m[FD_READ]); queue_m[FD_READ] = -1; } if (queue_m[FD_WRITE] != -1) { close(queue_m[FD_WRITE]); queue_m[FD_WRITE] = -1; } } int OamTask::initialize(sigset_t mask) { if (pipe(queue_m) == -1) { return -1; } mask_m = mask; return 0; } int OamTask::putq(CommonData & commonData) { int length = commonData.getLength(); char * data = commonData.getData(); if (length <= 0 || data == 0) { perror("the length or the data ptr is equal with 0."); return -1; } if (write(queue_m[FD_WRITE] , &length , sizeof(int)) != sizeof(int)) { if (errno == EINTR) { return 0; } perror("write syscall failed."); return -1; } if (write(queue_m[FD_WRITE] , data , length) != length) { if (errno == EINTR) { return 0; } perror("write syscall failed."); return -1; } return 0; } int OamTask::getq(CommonData & commonData) { int length = 0; if (read(queue_m[FD_READ] , &length , sizeof(int)) != sizeof(int)) { if (errno == EINTR) { return 0; } perror("read syscall failed."); return -1; } if (length <= 0) { perror("the length is less and equal than 0."); return -1; } char * data = new char[length]; memset(data , 0x00 , length); if (read(queue_m[FD_READ] , data , length) != length) { if (errno == EINTR) { return 0; } perror("read syscall failed."); return -1; } commonData.setLength(length); commonData.setData(data); return 0; } int OamTask::handle(CommonData * pData) { return 0; } int OamTask::run() { sigset_t oldmask; pthread_sigmask(SIG_BLOCK , &mask_m , &oldmask); while (isRunning()) { CommonData commonData; if (getq(commonData) == -1) { perror("getq failed."); return -1; } if (handle(&commonData) == -1) { char * data = commonData.getData(); delete [] data; data = 0; perror("handle failed."); return -1; } char * data = commonData.getData(); if (data) { delete [] data; data = 0; } } return 0; }
oamRunner.h
#ifndef OAMRUNNER_H_ #define OAMRUNNER_H_ #include <pthread.h> class OamRunner; class OamThreadRunner { public: // the definition of the thread status enum { RUN, PEND, STOP }; OamThreadRunner(); virtual ~OamThreadRunner(); bool stop(); bool start(OamRunner * runner); bool suspend(); bool resume(); bool wait(); bool isRunning(); pthread_t self(); private: static void * threadFunc(void * args); // the thread id pthread_t tid_m; // the status of the thread int status_m; }; class OamRunner { friend class OamThreadRunner; public: OamRunner(); virtual ~OamRunner(); virtual bool stop(); virtual bool start(); virtual bool suspend(); virtual bool resume(); virtual bool wait(); virtual bool isRunning(); pthread_t self(); protected: virtual int run(); private: // the object of the runner helper. OamThreadRunner runner_m; }; #endif
oamRunner.cc
#include "oamRunner.h" OamRunner::OamRunner(){} OamRunner::~OamRunner(){} int OamRunner::run() { return 0; } bool OamRunner::stop() { return runner_m.stop(); } bool OamRunner::start() { return runner_m.start(this); } bool OamRunner::suspend() { return runner_m.suspend(); } bool OamRunner::resume() { return runner_m.resume(); } bool OamRunner::wait() { return runner_m.wait(); } pthread_t OamRunner::self() { return runner_m.self(); } bool OamRunner::isRunning() { return runner_m.isRunning(); } OamThreadRunner::OamThreadRunner():tid_m(0) , status_m(STOP) {} OamThreadRunner::~OamThreadRunner() { status_m = STOP; } bool OamThreadRunner::stop() { if (status_m != STOP) { pthread_cancel(this->self()); status_m = STOP; return true; } return false; } bool OamThreadRunner::start(OamRunner * runner) { if (status_m == STOP && pthread_create(&tid_m , 0 , OamThreadRunner::threadFunc , runner) != 0) { return false; } if (status_m == STOP) { status_m = RUN; } return true; } bool OamThreadRunner::suspend() { return true; } bool OamThreadRunner::resume() { return true; } bool OamThreadRunner::wait() { return ((pthread_join(this->self() , 0) == 0)?true:false); } pthread_t OamThreadRunner::self() { return tid_m; } bool OamThreadRunner::isRunning() { pthread_testcancel(); return (status_m == STOP? false:true); } void * OamThreadRunner::threadFunc(void * args) { OamRunner * runner = (OamRunner *)args; runner->run(); return 0; }
test.cc
#include "ITimer.h" #include "TimerManager.h" #include "TimerCache.h" #include "TimerHandler.h" class MyTimer:public ITimer { public: void timeout(int timerId , void * args) { char * str = (char *)args; printf("%d:%s\n" , timerId , str); } }; int main(int argc, char ** argv) { TimerCache * pCache = new TimerCache; TimerManager * mgr = new TimerManager; mgr->initialize(pCache); int ret = TimerHandler::instance()->initialize(pCache); char * str = "hello world!"; for (int i =0;i < 1000;i++) { timer_t timerId = mgr->createTimer(new MyTimer , 2 , true , (void *)str); } TimerHandler::instance()->wait(); return 0; }
http://blog.sina.com.cn/s/blog_49b191150100kx0p.html