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