【聲明:版權所有,歡迎轉載,請勿用于商業用途。 聯系信箱:feixiaoxing @163.com】
定時器是我們在平時開發中經常使用到的工具,特别是在協定的編寫上更是必不可少的組成部分。雖然系統本身給我們提供了定時器,但是有的時候,我們也想自己編寫一個粗粒度的定時器,比如說在單元測試的時候。大家隻要看到下面的執行個體代碼,其實就會發現,隻要利用一下sleep函數,編寫屬于自己的定時器原來不是一件複雜的事情。當然,在實作自己的定時器之前,你需要明白自己的定時器應該設計成什麼樣子?比如說,
(1)定時器是否需要做互斥處理?
(2)定時器支援那幾種類型?
(3)定時器支援的最大粒度是多少?有沒有什麼限制?
(4)定時器的接口是什麼?
(5)定時器怎麼周遊、組織和運作?
下面的代碼就是我自己練習時編寫的一個定時器,具有下面幾個特點:
(1)支援1s為基本機關的定時操作;
(2)支援定時器互斥操作,适合移植;
(3)支援單次和循環兩種定時器;
(4)tick計數和定時函數處理是由不同線程完成;
(5)定時器接口簡單,和linux定時器接口基本一緻。
最後貼出自己的定時器代碼,歡迎大家多提寶貴意見。
struct TIMER
{
int type;
int state;
int count;
int expire;
void (*func)(void*);
void* param;
struct LINK_NODE node;
char name[MAX_NAME_LEN];
};
#define MAX_NAME_LEN 16
#define TIMER_LOCK_INIT()
#define TIMER_LOCK(sem)
#define TIMER_UNLOCK(sem)
#define STATUS int
#define MAX_TIMER_VALUE (7*24*3600)
enum
{
SINGLE_SHOT = 1,
RECYCLE_TYPE = 2
};
enum
{
TIMER_ACTIVE = 1,
TIMER_NOT_ACTIVE = 2
};
static int g_timer_count;
static struct LINK_NODE g_timer_head;
static HANDLE h_timer_sem;
void timer_init()
{
g_timer_count = 0;
link_init(&g_timer_head);
h_timer_sem = TIMER_LOCK_INIT();
}
STATUS alloc_timer(const char* name, int type, int count, void (*func)(void*), void* param)
{
struct LINK_NODE* p_node;
struct TIMER* p_timer;
if(NULL == name || NULL == func || NULL == param)
{
return FALSE;
}
if(strlen(name) >= MAX_NAME_LEN)
{
return FALSE;
}
if(SINGLE_SHOT != type && RECYCLE_TYPE != type)
{
return FALSE;
}
if(MAX_TIMER_VALUE < count || 0 == count)
{
return FALSE;
}
TIMER_LOCK(h_timer_sem);
for(p_node = g_timer_head.next; NULL != p_node; p_node = p_node->next)
{
p_timer = GET_DATA_BY_ADDRESS(p_node, struct TIMER, node);
if(0 == strncmp(p_timer->name, name, strlen(name)))
{
TIMER_UNLOCK(h_timer_sem);
return FALSE;
}
}
p_timer = (struct TIMER*)malloc(sizeof(struct TIMER));
if(NULL == p_timer)
{
TIMER_UNLOCK(h_timer_sem);
return FALSE;
}
memset(p_timer, 0, sizeof(struct TIMER));
strncpy(p_timer->name, name, strlen(name));
p_timer->type = type;
p_timer->count = count;
p_timer->func = func;
p_timer->param = param;
p_timer->state = TIMER_NOT_ACTIVE;
add_node_into_link(&p_timer->node, &g_timer_head);
TIMER_UNLOCK(h_timer_sem);
return TRUE;
}
STATUS timer_start(const char* name)
{
struct LINK_NODE* p_node;
struct TIMER* p_timer;
if(NULL == name || strlen(name) >= MAX_NAME_LEN)
{
return FALSE;
}
TIMER_LOCK(h_timer_sem);
for(p_node = g_timer_head.next; NULL != p_node; p_node = p_node->next)
{
p_timer = GET_DATA_BY_ADDRESS(p_node, struct TIMER, node);
if(0 == strncmp(p_timer->name, name, strlen(name)))
{
break;
}
}
if(NULL == p_node)
{
TIMER_UNLOCK(h_timer_sem);
return FALSE;
}
if(TIMER_NOT_ACTIVE == p_timer->state)
{
p_timer->expire = g_timer_count + p_timer->count;
p_timer->state = TIMER_ACTIVE;
}
TIMER_UNLOCK(h_timer_sem);
return TRUE;
}
STATUS timer_del(const char* name)
{
struct LINK_NODE* p_node;
struct TIMER* p_timer;
if(NULL == name || strlen(name) >= MAX_NAME_LEN)
{
return FALSE;
}
TIMER_LOCK(h_timer_sem);
for(p_node = g_timer_head.next; NULL != p_node; p_node = p_node->next)
{
p_timer = GET_DATA_BY_ADDRESS(p_node, struct TIMER, node);
if(0 == strncmp(p_timer->name, name, strlen(name)))
{
break;
}
}
if(NULL == p_node)
{
TIMER_UNLOCK(h_timer_sem);
return FALSE;
}
delete_node_from_link(&p_timer->node);
TIMER_UNLOCK(h_timer_sem);
free(p_timer);
return TRUE;
}
void timer_run()
{
struct LINK_NODE* p_node;
struct TIMER* p_timer;
int count;
while(1)
{
count = g_timer_count;
TIMER_LOCK(h_timer_sem);
for(p_node = g_timer_head.next; NULL != p_node; p_node = p_node->next)
{
p_timer = GET_DATA_BY_ADDRESS(p_node, struct TIMER, node);
if(TIMER_ACTIVE == p_timer->state && count > p_timer->expire)
{
p_timer->func(p_timer->param);
if(SINGLE_SHOT == p_timer->type)
{
p_timer->state = TIMER_NOT_ACTIVE;
}
else
{
p_timer->expire = count + p_timer->count;
}
}
}
TIMER_UNLOCK(h_timer_sem);
sleep(1);
}
}
void tick_process()
{
while(1)
{
g_timer_count ++;
sleep(1);
}
}