timer相关

以下代码来源: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

TimerManager.cc

#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





你可能感兴趣的:(timer相关)