时间轮 (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,可以在注册的回调函数中再次的注册自己。以下是实现代码:
// 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 ;
}
完整代码下载:百度云盘