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函数)
}

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;
}

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()
{
}

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;
}

 

版权声明:本文为share-ideas原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/share-ideas/p/10896369.html