定时器SDK

定时器是一切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;
}

 

posted @ 2015-09-30 11:24  guoyinglin  阅读(807)  评论(0编辑  收藏  举报