(1)時間輪樣貌
(2)源代碼及註釋
#ifndef TIME_WHEEL
#define TIME_WHEEL
#include <stdio.h>
#include <math.h>
template <typename T> //T是客戶類,應包含定時器
class tw_timer //定時器類
{
public:
int rotation; //時間輪轉多少圈後定時器會到期
T *user_data; //客戶數據
//定時器存於鏈表中
tw_timer *prev; //指向後繼節點
tw_timer *next; //指向前驅節點
void (*cb_func)(T*); //定時器到期時調用的函數
public:
tw_timer(int _rota, T *_user, void (*_cb_func)(T*))
:rotation(_rota), user_data(_user), cb_func(_cb_func),
prev(NULL), next(NULL) { };
//默認構造函數,用於構造時間輪上各鏈表的頭結點
tw_timer(): prev(NULL), next(NULL) { };
};
template <typename T>
class time_wheel //時間輪類
{
private:
int N; //時間輪上的槽的個數
int SI; //時間輪轉動一步所表示的時間跨度,通常以秒爲單位
//指向包含N個定時器對象的數組,以此表示時間輪
//這裏的每個定時器對象都只是各槽所擁有的鏈表的頭結點
tw_timer<T>* slots;
int cur_slot; //當前指針指向的槽
public:
//構造函數,創建各鏈表的頭結點
time_wheel(int _N, int _SI)
:N(_N), SI(_SI),slots(new tw_timer<T>[N]), cur_slot(0) { };
~time_wheel()
{
for(int i = 0;i < N;++i)
{
//將各鏈表除頭結點之外的結點都銷燬
tw_timer<T> *cur = slots[i].next, *temp;
while(cur)
{
temp = cur->next;
delete cur;
cur = temp;
}
}
delete[] slots; //銷燬頭結點數組
}
public:
//給定定時時間,客戶數據以及回調函數,創建一個定時器並插入到時間輪中,最後返回
tw_timer<T>* add_timer(int timeout, T *user, void (*cb_func)(T*))
{
if(timeout <= 0)
{
return NULL;
}
//每一步的時間跨度不一定能整除定時時間,這裏向上取整
int n_slot = ceil((double)timeout/SI);
int rotation = n_slot/N; //計算時間輪需要轉的圈數
int time_slot = (cur_slot + n_slot)%N; //計算此定時器將插入的槽
//動態創建一個定時器
tw_timer<T> *timer = new tw_timer<T>(rotation, user, cb_func);
//將定時器插入對應的槽所擁有的鏈表內
timer->next = slots[time_slot].next;
timer->prev = &slots[time_slot];
if(slots[time_slot].next)
{
slots[time_slot].next->prev = timer;
}
slots[time_slot].next = timer;
return timer;
}
//給定一個定時器,將其從時間輪上刪除
void del_timer(tw_timer<T>* timer)
{
if(!timer)
{
return;
}
timer->prev->next = timer->next;
if(timer->next)
{
timer->next->prev = timer->prev;
}
delete timer;
}
//時間輪每轉動一步,就檢查指針指向的當前槽內有無定時器到期
void tick()
{
cur_slot = (cur_slot + 1)%N; //時間輪向前轉動一步,指針指向下一個槽
tw_timer<T> *cur = slots[cur_slot].next, *temp; //獲得首個定時器結點
while(cur)
{
temp = cur->next;
if(!cur->rotation) //若定時器內的圈數爲0,則表明此定時器到期
{
cur->cb_func(cur->user_data); //執行回調函數
del_timer(cur); //刪除定時器
}
else
{
cur->rotation--; //圈數減1
}
cur = temp;
}
}
};
#endif