毫秒级定时器模块的设计与实现

0、引言

  定时器在服务器的通信模块中会广泛使用到,通过定时器可以相应的高效实现业务逻辑。由于一般给出的定时器都是以秒作为最小单元来处理的,大部分场景能够满足要求,但在一些特殊场景需要实现更精确的定时任务,这时候,就有必要去构建一个毫秒级的定时管理模块。因而本文分享了一种定时器管理模块的实现方法,同时给出了相应的使用案例,希望对读者有一定的帮助。

1、毫秒级的时间类型

首先构建一个毫秒级的类型,并对相应的运算符进行了重载,具体代码示例如下:

#ifdef LINUX
    #include <sys/time.h>
#endif

#ifdef IOS
    #include <sys/_types/_timeval.h>
#endif

#ifdef WIN32
    #include <winsock.h>
#endif

class Time
{
private:
    struct timeval time_val;
public:
    Time();
    ~Time();
    Time(const Time& other);
    Time(const struct timeval& timeVal);
    Time& operator=(const Time& other);
    Time& operator=(const struct timeval& timeVal);
    bool operator==(const Time& other);
    bool operator<(const Time& other);
    Time& operator+=(int val);

    time_t getSecond();
}

Time::Time()
{
    memset(time_val, 0, sizeof(struct timeval));
}
Time::Time(const Time& other)
{
    time_val = other.time_val;
}

Time::Time(const struct timeval& timeVal)
{
    time_val = timeVal;
}
Time& operator=(const Time& other)
{
    time_val = other.time_val;
    return *this;
}
Time& operator=(const struct timeval& timeVal)
{
    time_val = timeVal;
    return *this;
}
bool operator==(const Time& other)
{
    if (time_val.tv_sec != other.time_val.tv_sec ||
        time_val.tv_usec != other.time_val.tv_usec )
    {
        return false;
    }
    return true;
}
bool operator<(const Time& other)
{
    if (time_val.tv_sec < other.time_val.tv_sec)
    {
        return true;
    }
    else if (time_val.tv_sec == other.time_val.tv_sec)
    {
        if (time_val.tv_usec < other.time_val.tv_usec)
        {
            return true;
        }
    }
    return false;
}
Time& operator+=(int val)
{
    time_val.tv_usec += val*1000;
    time_val.tv_sec += time_val.tv_usec/1000000;
    time_val.tv_usec = time_val.tv_usec % 1000000;
}
time_t getSecond()
{
    return time_val.tv_sec;
}

 

2.定时任务的基类

  这可作为其他具体业务类型的基类,若该业务类型需要使用到定时器来执行定时任务,则应继承该类型。

class TimerObject
{
public:
    TimerObject(){};
    virtual ~TimerObject(){};
    virtual void DoSomething(int time_id, Time time_val); //当定时触发时,执行该函数
}

 

3.定时器节点的数据结构   

每个定时器对应一个定时器节点,相关参数有:每次定时的间隔时间、是否无限循环、触发的次数、具体执行定时任务的对象等

struct TimerNode
{
    int id;                //定时器节点的唯一标识
    int interval;        //定时的时间间隔
    Time startTime;        //开始定时的时间
    bool isForever;        //是否无限循环
    int totalCount;        //定时的总次数
    int curCount;        //当前定时已触发的次数
    TimerObject* obj;    //所触发定时任务的对象
    TimerNode* preTimerNode;    //使定时器节点之间形成一个链表
    TimerNode* nextTimerNode;
    TimerNode()
    {
        id = 0;
        interval = 0;
        isForever = false;
        totalCount = 0;
        curCount = 0;
        obj = NULL;
        preTimerNode = NULL;
        nextTimerNode = NULL;
    }
}

 

4.定时器管理的类型   

保存所有的定时器节点,并提供接口对相应的定时器节点进行操作,具体代码如下:

class TimerManager
{
private:
    TimerNode* head;
    map<int, TimerNode*> TimerNodes;
    int currentTimerNum;
    TimerNode* nextCheckNode;
    
    
public:
    TimerManager();
    ~TimerManager();
    int setTimer(TimerObject* obj, int interval, bool type=true, int total=0);
    void checkTimers(struct timeval& time);
    bool killTimer(int id);
    bool changeTimer(int id, int interval);
    
}

void checkTimers(struct timeval& time)
{
    //遍历所有的定时器,并执行定时器相应的任务(DoSomething函数)

MilliTime current_time(tNow);

// 在这个函数里面有可能会调用KillTimer,SetTimer
TimerNode* current_node = used_head->next_node;

next_check_node = NULL ;
if( current_node != NULL)
{
next_check_node = current_node->next_node ; //下一个节点,有可能被kill掉
}

while( current_node != NULL)
{
int timer_id = current_node->time_id ;

// 到达了触发次数
if(!current_node->loop_type && current_node->trigger_count == current_node->trigger_total )
{

}
// 没到点
else if( !(current_node->start_time + current_node->interval_time < current_time))
{

}
else
{
// 触发 :OnTimer有可能KillTimer,SetTimer,
current_node->timer_obj->OnTimer(timer_id,current_time);

// 该定时器id是否在OnTimer里面被kill掉了
if(TimerNodes.find(timer_id ) != TimerNodes.end())
{
current_node->start_time = current_time;
if(!current_node->loop_type)
{
current_node->trigger_count++;
}
}
}

current_node = next_check_node;
if(next_check_node)
{
next_check_node = next_check_node->next_node;
}
}

  

}

bool killTimer(int id)
{
    map<int TimerNode*>::iterator iter = TimerNodes.find(id);
    if (iter == TimerNodes.end())
    {
        return true;
    }
    TimerNode* delNode = iter->second;
    TimerNode* preNode = delNode->preTimerNode;
    TimerNode* nextNode = delNode->nextTimerNode;
    if (nextNode == NULL)
    {
        preNode->nextTimerNode = NULL;
    } else {
        preNode->nextTimerNode = nextNode;
        nextNode->preTimerNode = preNode;
    }
    
    TimerNodes.erase(iter);
    delete delNode;
    return true;
}

TimerManager()
{
    head = new TimerNode();
    int currentTimerNum = 0;
}

~TimerManager()
{
  TimerNode* p = null
  TimerNode* q = null
  p = head->nextTimerNode;
  while(p != null)
  {
    q = p
    p = p->nextTimerNode;
    delete q;
  }
  TimerNodes.clear();
}
int setTimer(TimerObject* obj, int interval, bool type, int total) { if(obj == NULL || total < 0 || (type == false && total == 0)) { return -1; } TimerNode* newNode = new TimerNode(); struct timeval now; getCurrentTime(&now); newNode->id = getTimerId(); newNode->startTime = Time(now); newNode->interval = interval; newNode->curCount = 0; newNode->totalCount = total; newNode->isForever = type; newNode->obj = obj; TimerNode* next = head->nextTimerNode; if (next) { head->nextTimerNode = newNode ; newNode->nextTimerNode = next ; newNode->preTimerNode = head ; next->preTimerNode = newNode ; } else { head->nextTimerNode = newNode; newNode->preTimerNode = head; } TimerNodes[newNode->id] = newNode; return newNode->id; } //取得一个空闲的id值 int getTimerId() {
  int id =
currentTimerNum++;
  if (id < 0)
  {
    currentTimerNum = 0;
    id = currentTimerNum++;
}
  map<int, TimerNode*>::iterator iter;
  while(true)
  {
    iter = TimerNodes.find(id);
    if (iter == TimerNodes.end())
    {
      return id;
    } else {
      id = currentTimerNum++;
      if (id < 0)
      {
        currentTimerNum = 0;
        id = currentTimerNum++;
      }
    }
  }
  
} void getCurrentTime(struct timeval* now) { #ifdef LINUX #ifdef IOS gettimeofday(now, NULL); #else struct timespec time_spec = {0, 0}; int get_spec = clock_gettime(CLOCK_MONOTONIC, &time_spec); if(get_spec == 0) { now->tv_sec = time_spec.tv_sec; now->tv_usec = time_spec.tv_nsec/1000; } else { now->tv_sec = 0 ; now->tv_usec = 0 ; } #endif #endif }

 

5.示例,展现如何使用定时器   

  一方面应构建一个继承TimeObject的Task类型,并且实现基类中的虚函数。另一方面,在main函数中构建定时器管理对象,且启动定时任务。最后,构建一个循环不断的检测所有的定时器,判断是否有定时器触发,若有触发,则执行对应的任务函数。用例的代码实现如下:

class Task : public TimeObject
{
private:
    int task_id;
    static TimerManager* timeMng;
    
public:
    Task()
    {
        task_id = -1;        
    }
    ~Task()
    {
        if (task_id != -1)
        {
            timeMng->killTimer(task_id);
        }
    }
    static void setTimeManager(TimerManager* timeM)
    {
        timeMng = timeM;
    }
    void start()
    {
        task_id = timeMng->setTimer(this, 10*1000, true, 0);
    }
    
    void DoSomething(int time_id, Time time_val)
    {
        if (task_id == time_id)
        {
            //执行定时任务
        }
    }
    
}

int main()
{
    TimerManager* timeMng = new TimerManager();
    Task* task = new Task();
    Task::setTimeManager(timeMng);
    task->start();
    
    while(1)
    {
        struct timeval now;
        getCurrentTime(&now);
        timeMng->checkTimers(now);
        sleep(1);
    }
    
    return 0;
}

 

posted @ 2019-05-20 20:53  zmlgo  阅读(1555)  评论(1编辑  收藏  举报