定时器是一切SDK的根本,欲写SDK必先确定定时器,定时器效率的高低决定着SDK函数的效率,下面是我个人写的Linux C++服务器端进程SDK中的定时器,部分参照了ACE和RocketMQ定时器的思想,欢迎大家拍砖,一起改进,共同进步。
#ifndef _TIME_THREAD_H
#define _TIME_THREAD_H
#include <list>
#include <map>
class TimerHandler
{
public:
TimerHandler()
{
}
virtual ~TimerHandler()
{
}
virtual void OnTimeOut(unsigned int timerID,void * pOtherArg) = 0;
};
typedef struct tagTimerlnfo
{
unsigned int id;
unsigned int elapse;
int outTime;// 初始化可以为负数,这样就可以延迟启动了
bool persistent;
TimerHandler * pTimerHandler;
void * pOtherArg;
}TimerInfo;
class TimerThread
{
public:
TimerThread();
~TimerThread();
void Start();
void Close();
unsigned int RegisterTimer(unsigned int initialDelay, unsigned int elapse, TimerHandler *pHandler, void * pOtherArg, bool persistent = true);
bool UnRegisterTimer(unsigned int timerId);
bool ResetTimer(unsigned int timerId);
bool IsRunning(){return m_bIsRunning;}
private:
void CheckTimeOut(unsigned int elapse, std::list<TimerInfo>& timerList, int& minWaitTime);
unsigned int GetNextTimerID();
static void* ThreadRoute(void* pArg);
private:
unsigned int s_nextTimerID;
std::map<unsigned int, TimerInfo> m_timers;
pthread_mutex_t m_mutex;
pthread_mutex_t m_startMutex;
pthread_cond_t m_cond;
bool m_bClosed;
bool m_bIsRunning;
pthread_t m_threadId;
};
#endif
#include <string.h>
#include <errno.h>
#include "log.h"
#include "common.h"
#include "TimeThread.h"
TimerThread::TimerThread():m_bClosed(false)
{
s_nextTimerID = 0;
pthread_cond_init(&m_cond,NULL);
pthread_mutex_init(&m_mutex,NULL);
pthread_mutex_init(&m_startMutex,NULL);
m_bIsRunning = false;
}
TimerThread::~TimerThread()
{
pthread_cond_destroy(&m_cond);
pthread_mutex_destroy(&m_mutex);
pthread_mutex_destroy(&m_startMutex);
}
void* TimerThread::ThreadRoute(void* pArg)
{
TimerThread *pTimerThread = (TimerThread*)pArg;
unsigned long long lastCheckTime = GetCurrentTimeMillis();
unsigned long long currentCheckTime = lastCheckTime;
int delayTime = 0;
std::list<TimerInfo> timerList;
while (!pTimerThread->m_bClosed)
{
currentCheckTime = GetCurrentTimeMillis();
unsigned int elapse = (unsigned int)(currentCheckTime - lastCheckTime);
timerList.clear();
pTimerThread->CheckTimeOut(elapse,timerList,delayTime);
if (!timerList.empty())
{
std::list<TimerInfo>::iterator it = timerList.begin();
for (; it != timerList.end(); it++)
{
it->pTimerHandler->OnTimeOut(it->id,it->pOtherArg);
//外部释放
/*
if (it->persistent == false)
{
delete it->pTimerHandler;
}
*/
}
}
unsigned long long checkEndTime = GetCurrentTimeMillis();
lastCheckTime = currentCheckTime;
int sleepTime = delayTime - (int)(checkEndTime -currentCheckTime);
if (sleepTime <= 0)
{
sleepTime = 0;
}
else
{
//usleep(sleepTime * 1000);
//struct timespec tv;
//tv.tv_sec = sleepTime / 1000;
//tv.tv_nsec = (sleepTime % 1000) * 1000000;
//nanosleep(&tv, 0);
pthread_mutex_lock(&pTimerThread->m_mutex);
struct timespec abstime = CalcAbsTime(sleepTime);
pthread_cond_timedwait(&pTimerThread->m_cond, &pTimerThread->m_mutex, &abstime);
pthread_mutex_unlock(&pTimerThread->m_mutex);
}
}
pTimerThread->m_bIsRunning = false;
return 0;
}
void TimerThread::Start()
{
pthread_mutex_lock(&m_startMutex);//同一个定时器避免启动两次
if (!m_bIsRunning)
{
pthread_attr_t attr;
int retcode = 0;
retcode = pthread_attr_init(&attr);
if(retcode != 0)
{
pthread_mutex_unlock(&m_startMutex);
nDebugLog(LOG_PRIORITY_ERROR, "pthread_attr_init failed:%s!",strerror(errno));
return;
}
pthread_t id;
retcode = pthread_create(&id, &attr, ThreadRoute, (void *)this);
if(retcode != 0)
{
pthread_mutex_unlock(&m_startMutex);
nDebugLog(LOG_PRIORITY_ERROR, "pthread_create failed:%s!",strerror(errno));
return;
}
m_threadId = id;
pthread_attr_destroy(&attr);
m_bIsRunning = true;
}
pthread_mutex_unlock(&m_startMutex);
}
void TimerThread::Close()
{
m_bClosed = true;
pthread_mutex_lock(&m_mutex);
pthread_cond_signal(&m_cond);
pthread_mutex_unlock(&m_mutex);
pthread_join(m_threadId, NULL);
}
void TimerThread::CheckTimeOut(unsigned int elapse, std::list<TimerInfo> &timerList, int& minWaitTime)
{
int tmpWait = 0;
minWaitTime = 0;
pthread_mutex_lock(&m_mutex);
if (!m_timers.empty())
{
std::map<unsigned int, TimerInfo>::iterator it = m_timers.begin();
while (it != m_timers.end())
{
it->second.outTime += elapse;
tmpWait = it->second.outTime - int(it->second.elapse);
if (tmpWait >= 0)
{
timerList.push_back(it->second);
if (it->second.persistent)
{
it->second.outTime = 0;
++it;
}
else
{
m_timers.erase(it++);
}
}
else
{
tmpWait = tmpWait * -1;
if (minWaitTime == 0)
{
minWaitTime = tmpWait;
}
else if (minWaitTime > tmpWait)
{
minWaitTime = tmpWait;
}
++it;
}
}
}
else
{
pthread_cond_wait(&m_cond, &m_mutex);
}
pthread_mutex_unlock(&m_mutex);
}
unsigned int TimerThread::RegisterTimer(unsigned int initialDelay,unsigned int elapse, TimerHandler *pHandler, void * pOtherArg, bool persistent)
{
TimerInfo info;
info.elapse = elapse;
info.outTime = 0-initialDelay;
info.pTimerHandler = pHandler;
info.persistent = persistent;
info.pOtherArg = pOtherArg;
pthread_mutex_lock(&m_mutex);
info.id = GetNextTimerID();
m_timers[info.id] = info;
pthread_cond_signal(&m_cond);
pthread_mutex_unlock(&m_mutex);
return info.id;
}
bool TimerThread::UnRegisterTimer(unsigned int timerId)
{
bool result = false;
pthread_mutex_lock(&m_mutex);
std::map<unsigned int, TimerInfo>::iterator it = m_timers.find(timerId);
if (it != m_timers.end())
{
m_timers.erase(it);
result = true;
}
pthread_mutex_unlock(&m_mutex);
return result;
}
bool TimerThread::ResetTimer(unsigned int timerId)
{
bool result = false;
pthread_mutex_lock(&m_mutex);
std::map<unsigned int, TimerInfo>::iterator it = m_timers.find(timerId);
if (it != m_timers.end())
{
if (it->second.persistent)
{
it->second.outTime = it->second.elapse;
}
else
{
it->second.outTime = 0;
}
result = true;
}
pthread_mutex_unlock(&m_mutex);
return result;
}
unsigned int TimerThread::GetNextTimerID()
{
if (s_nextTimerID > 10000000)
{
s_nextTimerID = 0;
}
else
{
++s_nextTimerID;
}
return s_nextTimerID;
}