0、引言
定时器在服务器的通信模块中会广泛使用到,通过定时器可以相应的高效实现业务逻辑。由于一般给出的定时器都是以秒作为最小单元来处理的,大部分场景能够满足要求,但在一些特殊场景需要实现更精确的定时任务,这时候,就有必要去构建一个毫秒级的定时管理模块。因而本文分享了一种定时器管理模块的实现方法,同时给出了相应的使用案例,希望对读者有一定的帮助。
1、毫秒级的时间类型
首先构建一个毫秒级的类型,并对相应的运算符进行了重载,具体代码示例如下:
#ifdef LINUX #include#endif#ifdef IOS #include #endif#ifdef WIN32 #include #endifclass 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; mapTimerNodes; 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 ::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;}