【声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱: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); } }