時間輪 (Timing-Wheel) 算法相似於一以恆定速度旋轉的左輪手槍,槍的撞針則撞擊槍膛,若是槍膛中有子彈,則會被擊發;與之相對應的是:對於 PerTickBookkeeping,其最本質的工做在於以 Tick 爲單位增長時鐘,若是發現有任何定時器到期,則調用相應的 ExpiryProcessing。設定一個循環爲 N 個 Tick 單元,當前時間是在 S 個循環以後指向元素 i (i>=0 and i<= N - 1),則當前時間 (Current Time)Tc 能夠表示爲:Tc = S*N + i ;若是此時插入一個時間間隔 (Time Interval) 爲 Ti 的定時器,設定它將會放入元素 n(Next) 中,則 n = (Tc + Ti)mod N = (S*N + i + Ti) mod N = (i + Ti) mod N 。若是咱們的 N 足夠的大,顯然 StartTimer,StopTimer,PerTickBookkeeping 時,算法複雜度分別爲 O(1),O(1),O(1) 。下圖是一個簡單的時間輪定時器: 算法
若是須要支持的定時器範圍很是的大,上面的實現方式則不能知足這樣的需求。由於這樣將消耗很是可觀的內存,假設須要表示的定時器範圍爲:0 – 2^3-1ticks,則簡單時間輪須要 2^32 個元素空間,這對於內存空間的使用將很是的龐大。也許能夠下降定時器的精度,使得每一個 Tick 表示的時間更長一些,但這樣的代價是定時器的精度將大打折扣。如今的問題是,度量定時器的粒度,只能使用惟一粒度嗎?想一想平常生活中常遇到的水錶,以下圖 : 數組
在上面的水錶中,爲了表示度量範圍,分紅了不一樣的單位,好比 1000,100,10 等等,類似的,表示一個 32bits 的範圍,也不須要 2^32 個元素的數組。實際上,Linux 的內核把定時器分爲 5 組,每組的粒度(對應水錶例子的單位)分別表示爲:1 jiffies,256 jiffies,256*64 jiffies,256*64*64 jiffies,256*64*64*64 jiffies,每組中桶的數量分別爲:256,64,64,64,64,能表示的範圍爲 2^32 。有了這樣的實現,驅動內核定時器的機制也能夠經過水錶的例子來理解了,就像水錶,每一個粒度上都有一個指針指向當前時間,時間以固定 tick 遞增,而當前時間指針則也依次遞增,若是發現當前指針的位置能夠肯定爲一個註冊的定時器,就觸發其註冊的回調函數。 Linux 內核定時器本質上是 Single-Shot Timer,若是想成爲 Repeating Timer,能夠在註冊的回調函數中再次的註冊本身。如下是實現代碼: app
// def.h #ifndef _DEF_H_ #define _DEF_H_ #if defined(_WIN32) || defined(_WIN64) #define STDCALL __stdcall #else #define STDCALL __attribute__((stdcall)) #endif //基本數據類型定義 typedef char int8 ; typedef unsigned char uint8 ; typedef uint8 byte ; typedef short int16 ; typedef unsigned short uint16 ; typedef long int32 ; typedef unsigned long uint32 ; #endif //_DEF_H_
// Lock.h 同步鎖 #ifndef _LOCK_H_ #define _LOCK_H_ #if defined(_WIN32) || defined(_WIN64) #include <Windows.h> typedef CRITICAL_SECTION LOCK ; #else #include <pthread.h> typedef pthread_mutex_t LOCK ; #endif void InitLock(LOCK *pLock) ; void UninitLock(LOCK *pLock) ; void Lock(LOCK *pLock) ; void Unlock(LOCK *pLock) ; #endif //_LOCK_H_
// Lock.c 同步鎖 #include "Lock.h" void InitLock(LOCK *pLock) { #if defined(_WIN32) || defined(_WIN64) InitializeCriticalSection(pLock) ; #else pthread_mutex_init(pLock, NULL); #endif } void UninitLock(LOCK *pLock) { #if defined(_WIN32) || defined(_WIN64) DeleteCriticalSection(pLock) ; #else pthread_mutex_destroy(pLock); #endif } void Lock(LOCK *pLock) { #if defined(_WIN32) || defined(_WIN64) EnterCriticalSection(pLock) ; #else pthread_mutex_lock(pLock); #endif } void Unlock(LOCK *pLock) { #if defined(_WIN32) || defined(_WIN64) LeaveCriticalSection(pLock) ; #else pthread_mutex_unlock(pLock); #endif }
// Thread.h 定時器調度線程 #ifndef _THREAD_H_ #define _THREAD_H_ #if defined(_WIN32) || defined(_WIN64) #include <Windows.h> #include <process.h> //_beginthreadex() typedef HANDLE THREAD ; #else #include <pthread.h> typedef pthread_t THREAD ; #endif #include "def.h" typedef void* (*FNTHREAD)(void *pParam); THREAD ThreadCreate(FNTHREAD fnThreadProc, void *pParam) ; void ThreadJoin(THREAD thread) ; void ThreadDestroy(THREAD thread) ; #endif //_THREAD_H_
// Thread.c 定時器調度線程 #include "Thread.h" THREAD ThreadCreate(FNTHREAD fnThreadProc, void *pParam) { #if defined(_WIN32) || defined(_WIN64) if(fnThreadProc == NULL) return NULL ; return (THREAD)_beginthreadex(NULL, 0, (LPTHREAD_START_ROUTINE)fnThreadProc, pParam, 0, NULL) ; #else THREAD t ; if(fnThreadProc == NULL) return 0 ; if(pthread_create(&t, NULL, fnThreadProc, pParam) == 0) return t ; else return (THREAD)0 ; #endif } void ThreadJoin(THREAD thread) { #if defined(_WIN32) || defined(_WIN64) WaitForSingleObject(thread, INFINITE) ; #else pthread_join(thread, NULL) ; #endif } void ThreadDestroy(THREAD thread) { #if defined(_WIN32) || defined(_WIN64) CloseHandle(thread) ; #else // #endif }
// Timer.h #ifndef _TIMER_H_ #define _TIMER_H_ #include "def.h" #include "Lock.h" #include "Thread.h" #define CONFIG_BASE_SMALL 0 //TVN_SIZE=64 TVR_SIZE=256 #define TVN_BITS (CONFIG_BASE_SMALL ? 4 : 6) #define TVR_BITS (CONFIG_BASE_SMALL ? 6 : 8) #define TVN_SIZE (1 << TVN_BITS) #define TVR_SIZE (1 << TVR_BITS) #define TVN_MASK (TVN_SIZE - 1) #define TVR_MASK (TVR_SIZE - 1) #define MAX_TVAL ((unsigned long)((1ULL << (TVR_BITS + 4*TVN_BITS)) - 1)) #define TIME_AFTER(a,b) ((long)(b) - (long)(a) < 0) #define TIME_BEFORE(a,b) TIME_AFTER(b,a) #define TIME_AFTER_EQ(a,b) ((long)(a) - (long)(b) >= 0) #define TIME_BEFORE_EQ(a,b) TIME_AFTER_EQ(b,a) typedef void (STDCALL *FNTIMRCALLBACK)(void *pParam) ; typedef struct LIST_TIMER { struct LIST_TIMER *pPrev ; struct LIST_TIMER *pNext ; } LISTTIMER, *LPLISTTIMER ; typedef struct TIMER_NODE { struct LIST_TIMER ltTimer ; //定時器鏈表的入口 uint32 uExpires ; //定時器超時的時刻 uint32 uPeriod ; //間隔多長時間觸發一次 FNTIMRCALLBACK fnTimer ; //定時器處理函數 void *pParam ; //回調函數的參數 } TIMERNODE, *LPTIMERNODE ; typedef struct TIMER_MANAGER { LOCK lock ; //同步鎖 THREAD thread ; //線程句柄 uint32 uExitFlag ; //退出標識(0:Continue, other: Exit) uint32 uJiffies ; //基準時間(當前時間) struct LIST_TIMER arrListTimer1[TVR_SIZE] ; struct LIST_TIMER arrListTimer2[TVN_SIZE] ; struct LIST_TIMER arrListTimer3[TVN_SIZE] ; struct LIST_TIMER arrListTimer4[TVN_SIZE] ; struct LIST_TIMER arrListTimer5[TVN_SIZE] ; } TIMERMANAGER, *LPTIMERMANAGER ; void STDCALL SleepMilliseconds(uint32 uMs) ; //建立定時器管理器 LPTIMERMANAGER STDCALL CreateTimerManager(void) ; //刪除定時器管理器 void STDCALL DestroyTimerManager(LPTIMERMANAGER lpTimerManager) ; //建立一個定時器。fnTimer回調函數地址。pParam回調函數的參數。uDueTime首次觸發的超時時間間隔。uPeriod定時器循環週期,若爲0,則該定時器只運行一次。 LPTIMERNODE STDCALL CreateTimer(LPTIMERMANAGER lpTimerManager, FNTIMRCALLBACK fnTimer, void *pParam, uint32 uDueTime, uint32 uPeriod) ; //刪除定時器 int32 STDCALL DeleteTimer(LPTIMERMANAGER lpTimerManager, LPTIMERNODE lpTimer) ; #endif //_TIMER_H_
// Timer.c 定時器實現 #include <stddef.h> #include <stdlib.h> #if defined(_WIN32) || defined(_WIN64) #include <time.h> #else #include <sys/time.h> #endif #include "Timer.h" //獲取基準時間。 static uint32 GetJiffies_old(void) { #if defined(_WIN32) || defined(_WIN64) SYSTEMTIME st ; struct tm t ; GetLocalTime(&st); t.tm_year = st.wYear - 1900; t.tm_mon = st.wMonth - 1; t.tm_mday = st.wDay; t.tm_hour = st.wHour; t.tm_min = st.wMinute; t.tm_sec = st.wSecond; return (uint32)mktime(&t) * 1000 + st.wMilliseconds ; #else struct timeval tv ; gettimeofday(&tv, NULL) ; return tv.tv_sec * 1000 + tv.tv_usec / 1000 ; #endif } static uint32 GetJiffies(void) { #if defined(_WIN32) || defined(_WIN64) return GetTickCount() ; #else //需鏈接 rt庫,加-lrt參數 struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000); #endif } static void ListTimerInsert(struct LIST_TIMER *pNew, struct LIST_TIMER *pPrev, struct LIST_TIMER *pNext) { pNext->pPrev = pNew; pNew->pNext = pNext; pNew->pPrev = pPrev; pPrev->pNext = pNew; } static void ListTimerInsertHead(struct LIST_TIMER *pNew, struct LIST_TIMER *pHead) { ListTimerInsert(pNew, pHead, pHead->pNext); } static void ListTimerInsertTail(struct LIST_TIMER *pNew, struct LIST_TIMER *pHead) { ListTimerInsert(pNew, pHead->pPrev, pHead); } static void ListTimerReplace(struct LIST_TIMER *pOld, struct LIST_TIMER *pNew) { pNew->pNext = pOld->pNext ; pNew->pNext->pPrev = pNew ; pNew->pPrev = pOld->pPrev ; pNew->pPrev->pNext = pNew ; } static void ListTimerReplaceInit(struct LIST_TIMER *pOld, struct LIST_TIMER *pNew) { ListTimerReplace(pOld, pNew) ; pOld->pNext = pOld ; pOld->pPrev = pOld ; } static void InitArrayListTimer(struct LIST_TIMER *arrListTimer, uint32 nSize) { uint32 i ; for(i=0; i<nSize; i++) { arrListTimer[i].pPrev = &arrListTimer[i] ; arrListTimer[i].pNext = &arrListTimer[i] ; } } static void DeleteArrayListTimer(struct LIST_TIMER *arrListTimer, uint32 uSize) { struct LIST_TIMER listTmr, *pListTimer ; struct TIMER_NODE *pTmr ; uint32 idx ; for(idx=0; idx<uSize; idx++) { ListTimerReplaceInit(&arrListTimer[idx], &listTmr) ; pListTimer = listTmr.pNext ; while(pListTimer != &listTmr) { pTmr = (struct TIMER_NODE *)((uint8 *)pListTimer - offsetof(struct TIMER_NODE, ltTimer)) ; pListTimer = pListTimer->pNext ; free(pTmr) ; } } } static void AddTimer(LPTIMERMANAGER lpTimerManager, LPTIMERNODE pTmr) { struct LIST_TIMER *pHead ; uint32 i, uDueTime, uExpires ; // uExpires = pTmr->uExpires ; //定時器到期的時刻 uDueTime = uExpires - lpTimerManager->uJiffies ; if (uDueTime < TVR_SIZE) //idx < 256 (2的8次方) { i = uExpires & TVR_MASK; //expires & 255 pHead = &lpTimerManager->arrListTimer1[i] ; } else if (uDueTime < 1 << (TVR_BITS + TVN_BITS)) //idx < 16384 (2的14次方) { i = (uExpires >> TVR_BITS) & TVN_MASK; // i = (expires>>8) & 63 pHead = &lpTimerManager->arrListTimer2[i] ; } else if (uDueTime < 1 << (TVR_BITS + 2 * TVN_BITS)) // idx < 1048576 (2的20次方) { i = (uExpires >> (TVR_BITS + TVN_BITS)) & TVN_MASK; // i = (expires>>14) & 63 pHead = &lpTimerManager->arrListTimer3[i] ; } else if (uDueTime < 1 << (TVR_BITS + 3 * TVN_BITS)) // idx < 67108864 (2的26次方) { i = (uExpires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK; // i = (expires>>20) & 63 pHead = &lpTimerManager->arrListTimer4[i] ; } else if ((signed long) uDueTime < 0) { /* * Can happen if you add a timer with expires == jiffies, * or you set a timer to go off in the past */ pHead = &lpTimerManager->arrListTimer1[(lpTimerManager->uJiffies & TVR_MASK)]; } else { /* If the timeout is larger than 0xffffffff on 64-bit * architectures then we use the maximum timeout: */ if (uDueTime > 0xffffffffUL) { uDueTime = 0xffffffffUL; uExpires = uDueTime + lpTimerManager->uJiffies; } i = (uExpires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK; // i = (expires>>26) & 63 pHead = &lpTimerManager->arrListTimer5[i]; } ListTimerInsertTail(&pTmr->ltTimer, pHead) ; } static uint32 CascadeTimer(LPTIMERMANAGER lpTimerManager, struct LIST_TIMER *arrListTimer, uint32 idx) { struct LIST_TIMER listTmr, *pListTimer ; struct TIMER_NODE *pTmr ; ListTimerReplaceInit(&arrListTimer[idx], &listTmr) ; pListTimer = listTmr.pNext ; while(pListTimer != &listTmr) { pTmr = (struct TIMER_NODE *)((uint8 *)pListTimer - offsetof(struct TIMER_NODE, ltTimer)) ; pListTimer = pListTimer->pNext ; AddTimer(lpTimerManager, pTmr) ; } return idx ; } static void RunTimer(LPTIMERMANAGER lpTimerManager) { #define INDEX(N) ((lpTimerManager->uJiffies >> (TVR_BITS + (N) * TVN_BITS)) & TVN_MASK) uint32 idx, uJiffies ; struct LIST_TIMER listTmrExpire, *pListTmrExpire ; struct TIMER_NODE *pTmr ; if(NULL == lpTimerManager) return ; uJiffies = GetJiffies() ; Lock(&lpTimerManager->lock) ; while(TIME_AFTER_EQ(uJiffies, lpTimerManager->uJiffies)) { idx = lpTimerManager->uJiffies & TVR_MASK ; if (!idx && (!CascadeTimer(lpTimerManager, lpTimerManager->arrListTimer2, INDEX(0))) && (!CascadeTimer(lpTimerManager, lpTimerManager->arrListTimer3, INDEX(1))) && !CascadeTimer(lpTimerManager, lpTimerManager->arrListTimer4, INDEX(2))) CascadeTimer(lpTimerManager, lpTimerManager->arrListTimer5, INDEX(3)); //lpTimerManager->uJiffies++ ; pListTmrExpire = &listTmrExpire ; ListTimerReplaceInit(&lpTimerManager->arrListTimer1[idx], pListTmrExpire) ; pListTmrExpire = pListTmrExpire->pNext ; while(pListTmrExpire != &listTmrExpire) { pTmr = (struct TIMER_NODE *)((uint8 *)pListTmrExpire - offsetof(struct TIMER_NODE, ltTimer)) ; pListTmrExpire = pListTmrExpire->pNext ; pTmr->fnTimer(pTmr->pParam) ; // if(pTmr->uPeriod != 0) { pTmr->uExpires = lpTimerManager->uJiffies + pTmr->uPeriod ; AddTimer(lpTimerManager, pTmr) ; } else free(pTmr) ; } lpTimerManager->uJiffies++ ; } Unlock(&lpTimerManager->lock) ; } static void *ThreadRunTimer(void *pParam) { LPTIMERMANAGER pTimerMgr ; pTimerMgr = (LPTIMERMANAGER)pParam ; if(pTimerMgr == NULL) return NULL ; while(!pTimerMgr->uExitFlag) { RunTimer(pTimerMgr) ; SleepMilliseconds(1) ; } return NULL ; } void STDCALL SleepMilliseconds(uint32 uMs) { #if defined(_WIN32) || defined(_WIN64) Sleep(uMs) ; #else struct timeval tv; tv.tv_sec = 0 ; tv.tv_usec = uMs * 1000 ; select(0, NULL, NULL, NULL, &tv); #endif } //建立定時器管理器 LPTIMERMANAGER STDCALL CreateTimerManager(void) { LPTIMERMANAGER lpTimerMgr = (LPTIMERMANAGER)malloc(sizeof(TIMERMANAGER)) ; if(lpTimerMgr != NULL) { lpTimerMgr->thread = (THREAD)0 ; lpTimerMgr->uExitFlag = 0 ; InitLock(&lpTimerMgr->lock) ; lpTimerMgr->uJiffies = GetJiffies() ; InitArrayListTimer(lpTimerMgr->arrListTimer1, sizeof(lpTimerMgr->arrListTimer1)/sizeof(lpTimerMgr->arrListTimer1[0])) ; InitArrayListTimer(lpTimerMgr->arrListTimer2, sizeof(lpTimerMgr->arrListTimer2)/sizeof(lpTimerMgr->arrListTimer2[0])) ; InitArrayListTimer(lpTimerMgr->arrListTimer3, sizeof(lpTimerMgr->arrListTimer3)/sizeof(lpTimerMgr->arrListTimer3[0])) ; InitArrayListTimer(lpTimerMgr->arrListTimer4, sizeof(lpTimerMgr->arrListTimer4)/sizeof(lpTimerMgr->arrListTimer4[0])) ; InitArrayListTimer(lpTimerMgr->arrListTimer5, sizeof(lpTimerMgr->arrListTimer5)/sizeof(lpTimerMgr->arrListTimer5[0])) ; lpTimerMgr->thread = ThreadCreate(ThreadRunTimer, lpTimerMgr) ; } return lpTimerMgr ; } //刪除定時器管理器 void STDCALL DestroyTimerManager(LPTIMERMANAGER lpTimerManager) { if(NULL == lpTimerManager) return ; lpTimerManager->uExitFlag = 1 ; if((THREAD)0 != lpTimerManager->thread) { ThreadJoin(lpTimerManager->thread) ; ThreadDestroy(lpTimerManager->thread) ; lpTimerManager->thread = (THREAD)0 ; } DeleteArrayListTimer(lpTimerManager->arrListTimer1, sizeof(lpTimerManager->arrListTimer1)/sizeof(lpTimerManager->arrListTimer1[0])) ; DeleteArrayListTimer(lpTimerManager->arrListTimer2, sizeof(lpTimerManager->arrListTimer2)/sizeof(lpTimerManager->arrListTimer2[0])) ; DeleteArrayListTimer(lpTimerManager->arrListTimer3, sizeof(lpTimerManager->arrListTimer3)/sizeof(lpTimerManager->arrListTimer3[0])) ; DeleteArrayListTimer(lpTimerManager->arrListTimer4, sizeof(lpTimerManager->arrListTimer4)/sizeof(lpTimerManager->arrListTimer4[0])) ; DeleteArrayListTimer(lpTimerManager->arrListTimer5, sizeof(lpTimerManager->arrListTimer5)/sizeof(lpTimerManager->arrListTimer5[0])) ; UninitLock(&lpTimerManager->lock) ; free(lpTimerManager) ; } //建立一個定時器。fnTimer回調函數地址。pParam回調函數的參數。uDueTime首次觸發的超時時間間隔。uPeriod定時器循環週期,若爲0,則該定時器只運行一次。 LPTIMERNODE STDCALL CreateTimer(LPTIMERMANAGER lpTimerManager, FNTIMRCALLBACK fnTimer, void *pParam, uint32 uDueTime, uint32 uPeriod) { LPTIMERNODE pTmr = NULL ; if(NULL == fnTimer || NULL == lpTimerManager) return NULL ; pTmr = (LPTIMERNODE)malloc(sizeof(TIMERNODE)) ; if(pTmr != NULL) { pTmr->uPeriod = uPeriod ; pTmr->fnTimer = fnTimer ; pTmr->pParam = pParam ; // Lock(&lpTimerManager->lock) ; pTmr->uExpires = lpTimerManager->uJiffies + uDueTime ; AddTimer(lpTimerManager, pTmr) ; Unlock(&lpTimerManager->lock) ; } return pTmr ; } //刪除定時器 int32 STDCALL DeleteTimer(LPTIMERMANAGER lpTimerManager, LPTIMERNODE lpTimer) { struct LIST_TIMER *pListTmr ; if(NULL != lpTimerManager && NULL != lpTimer) { Lock(&lpTimerManager->lock) ; pListTmr = &lpTimer->ltTimer ; pListTmr->pPrev->pNext = pListTmr->pNext ; pListTmr->pNext->pPrev = pListTmr->pPrev ; free(lpTimer) ; Unlock(&lpTimerManager->lock) ; return 0 ; } else return -1 ; }
// main.c 測試例子 #include <stdio.h> #include "Timer.h" void STDCALL TimerFun(void *pParam) { LPTIMERMANAGER pMgr ; pMgr = (LPTIMERMANAGER)pParam ; printf("Timer expire! Jiffies: %lu\n", pMgr->uJiffies) ; } int main(void) { LPTIMERMANAGER pMgr ; LPTIMERNODE pTn ; pMgr = CreateTimerManager() ; CreateTimer(pMgr, TimerFun, pMgr, 2000, 0) ; pTn = CreateTimer(pMgr, TimerFun, pMgr, 4000, 1000) ; SleepMilliseconds(10001) ; DeleteTimer(pMgr, pTn) ; SleepMilliseconds(3000) ; DestroyTimerManager(pMgr) ; return 0 ; }
完整代碼下載:百度雲盤 函數