毫秒级定时器模块的设计与实现
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; }