Chinaunix首页 | 论坛 | 博客
  • 博客访问: 389159
  • 博文数量: 80
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 560
  • 用 户 组: 普通用户
  • 注册时间: 2015-03-10 08:38
文章分类
文章存档

2016年(32)

2015年(48)

我的朋友

分类: LINUX

2015-08-21 10:23:24

linux下多定时器的实现
一、已有的定时器接口
   时空管理是计算机系统的主要任务。在时间管理中,我们经常利用定时器处理事情:比如tcp协议中利用定时器管理包超时,视频显示中利用定时器来定时显示视频帧,web服务中利用定时器来管理用户的超时。windows系统提供了SetTimer和timeSetEvent等定时器接口,linux中则提供了setitimer等接口。这些函数的接口很类似,大体上都是用户提供回调函数和超时时间向OS注册一个定时器事件,OS在超时时间到了的时候,调用用户提供的回调函数来完成用户想要做的事情。windows下的接口支持单进程中拥有多个定时器,而linux则只允许单进程拥有一个定时器,因此在linux下的单进程中要使用多个定时器,则需要自己维护管理,这是本文写作的出发点。另外,OS提供的定时器管理算法在大规模定时器的管理方面可能还不尽人意,这时候就需要用户去优化管理算法了,本文在这方面提供了一点素材。

二、一个最简单的多定时器的实现(linux版)

1、实现细节 
  这个实现允许用户使用多个自定义的定时器,每个自定义的定时器将周期地被触发直到其被删除。实现的主要思路是:
    i)首先在初始化多定时器(init_mul_timer)时利用setitimer注册一个基本的时间单位(如1s)的定时事件;
    ii)用户需要set_a_timer注册
自定义定时器时,在timer_manage管理结构中记录这个定时器的回调函数和定时周期等参数;
    iii)当基本的时间单位到期后(如SIGALRM信号到达时),遍历整个timer_manage,如果有自定义定时器的超时时间到了,就执行相应的回调函数,并将
自定义定时器的超时时间置为最初值;否则将自定义定时器的超时时间相应地减一个基本的时间单位;
    iv)用户通过del_a_timer来删除某个定时器,通 过destroy_mul_timer来删除整个多定时器。
2、代码
i) mul_timer.h


  1. /* This file provides an interface of multiple timers. for convenience, it simplify signal processing.
  2.  * Also, it can't be used in multithreading environment.
  3.  * Author:bripengandre
  4.  * Date:2009-04-29
  5.  */
  6. #ifndef _MUL_TIMER_H_
  7. #define _MUL_TIMER_H_

  8. #include <sys/time.h>

  9. #define MAX_TIMER_CNT 10
  10. #define MUL_TIMER_RESET_SEC 10
  11. #define TIMER_UNIT 60
  12. #define MAX_FUNC_ARG_LEN 100
  13. #define INVALID_TIMER_HANDLE (-1)

  14. typedef int timer_handle_t;

  15. typedef struct _timer_manage
  16. {
  17.     struct _timer_info
  18.     {
  19.         int state; /* on or off */
  20.         int interval;
  21.         int elapse; /* 0~interval */
  22.         int (* timer_proc) (void *arg, int arg_len);
  23.         char func_arg[MAX_FUNC_ARG_LEN];
  24.         int arg_len;
  25.     }timer_info[MAX_TIMER_CNT];

  26.     void (* old_sigfunc)(int);
  27.     void (* new_sigfunc)(int);
  28.     struct itimerval value, ovalue;
  29. }_timer_manage_t;

  30. /* success, return 0; failed, return -1 */
  31. int init_mul_timer(void);
  32. /* success, return 0; failed, return -1 */
  33. int destroy_mul_timer(void);
  34. /* success, return timer handle(>=0); failed, return -1 */
  35. timer_handle_t set_a_timer(int interval, int (* timer_proc) (void *arg, int arg_len), void *arg, int arg_len);
  36. /* success, return 0; failed, return -1 */
  37. int del_a_timer(timer_handle_t handle);

  38. #endif /* _MUL_TIMER_H_ */

ii)mul_timer.c

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <signal.h>
  4. #include <time.h>
  5. #include "mul_timer.h"

  6. static struct _timer_manage timer_manage;

  7. static void sig_func(int signo);

  8. /* success, return 0; failed, return -1 */
  9. int init_mul_timer(void)
  10. {
  11.     int ret;
  12.     
  13.     memset(&timer_manage, 0, sizeof(struct _timer_manage));
  14.     if( (timer_manage.old_sigfunc = signal(SIGALRM, sig_func)) == SIG_ERR)
  15.     {
  16.         return (-1);
  17.     }
  18.     timer_manage.new_sigfunc = sig_func;
  19.     
  20.     timer_manage.value.it_value.tv_sec = MUL_TIMER_RESET_SEC;
  21.     timer_manage.value.it_value.tv_usec = 0;
  22.     timer_manage.value.it_interval.tv_sec = TIMER_UNIT;
  23.     timer_manage.value.it_interval.tv_usec = 0;
  24.     ret = setitimer(ITIMER_REAL, &timer_manage.value, &timer_manage.ovalue);
  25.     
  26.     return (ret);
  27. }


  28. /* success, return 0; failed, return -1 */
  29. int destroy_mul_timer(void)
  30. {
  31.     int ret;
  32.     
  33.     if( (signal(SIGALRM, timer_manage.old_sigfunc)) == SIG_ERR)
  34.     {
  35.         return (-1);

  36.     }

  37.     ret = setitimer(ITIMER_REAL, &timer_manage.ovalue, &timer_manage.value);
  38.     if(ret < 0)
  39.     {
  40.         return (-1);
  41.     }
  42.     memset(&timer_manage, 0, sizeof(struct _timer_manage));
  43.     
  44.     return(0);
  45. }


  46. /* success, return timer handle(>=0); failed, return -1 */
  47. timer_handle_t set_a_timer(int interval, int (* timer_proc) (void *arg, int arg_len), void *arg, int arg_len)
  48. {
  49.     int i;
  50.     
  51.     if(timer_proc == NULL || interval <= 0)
  52.     {
  53.         return (-1);
  54.     }
  55.     
  56.     for(i = 0; i < MAX_TIMER_CNT; i++)
  57.     {
  58.         if(timer_manage.timer_info[i].state == 1)
  59.         {
  60.             continue;
  61.         }
  62.         
  63.         memset(&timer_manage.timer_info[i], 0, sizeof(timer_manage.timer_info[i]));
  64.         timer_manage.timer_info[i].timer_proc = timer_proc;
  65.         if(arg != NULL)
  66.         {
  67.             if(arg_len > MAX_FUNC_ARG_LEN)
  68.             {
  69.                 return (-1);
  70.             }
  71.             memcpy(timer_manage.timer_info[i].func_arg, arg, arg_len);
  72.             timer_manage.timer_info[i].arg_len = arg_len;
  73.         }
  74.         timer_manage.timer_info[i].interval = interval;
  75.         timer_manage.timer_info[i].elapse = 0;
  76.         timer_manage.timer_info[i].state = 1;
  77.         break;
  78.     }
  79.     
  80.     if(i >= MAX_TIMER_CNT)
  81.     {
  82.         return (-1);
  83.     }
  84.     return (i);
  85. }


  86. /* success, return 0; failed, return -1 */
  87. int del_a_timer(timer_handle_t handle)
  88. {
  89.     if(handle < 0 || handle >= MAX_TIMER_CNT)
  90.     {
  91.         return (-1);
  92.     }
  93.     
  94.     memset(&timer_manage.timer_info[handle], 0, sizeof(timer_manage.timer_info[handle]));
  95.     
  96.     return (0);
  97. }


  98. static void sig_func(int signo)
  99. {
  100.     int i;
  101.     for(i = 0; i < MAX_TIMER_CNT; i++)
  102.     {
  103.         if(timer_manage.timer_info[i].state == 0)
  104.         {
  105.             continue;
  106.         }
  107.         timer_manage.timer_info[i].elapse++;
  108.         if(timer_manage.timer_info[i].elapse == timer_manage.timer_info[i].interval)
  109.         {
  110.             timer_manage.timer_info[i].elapse = 0;
  111.             timer_manage.timer_info[i].timer_proc(timer_manage.timer_info[i].func_arg, timer_manage.timer_info[i].arg_len);
  112.         }
  113.     }
  114. }


  115. #define _MUL_TIMER_MAIN


  116. #ifdef _MUL_TIMER_MAIN

  117. static void get_format_time(char *tstr)
  118. {
  119.     time_t t;
  120.     
  121.     t = time(NULL);
  122.     strcpy(tstr, ctime(&t));
  123.     tstr[strlen(tstr)-1] = '/0';
  124.     
  125.     return;
  126. }


  127. timer_handle_t hdl[3], call_cnt = 0;
  128. int timer_proc1(void *arg, int len)
  129. {
  130.     char tstr[200];
  131.     static int i, ret;
  132.     
  133.     get_format_time(tstr);
  134.     printf("hello %s: timer_proc1 is here./n", tstr);
  135.     if(i >= 5)
  136.     {
  137.         get_format_time(tstr);
  138.         ret = del_a_timer(hdl[0]);
  139.         printf("timer_proc1: %s del_a_timer::ret=%d/n", tstr, ret);
  140.     }
  141.     i++;
  142.     call_cnt++;
  143.     
  144.     
  145.     return (1);
  146. }

  147. int timer_proc2(void * arg, int len)
  148. {
  149.     char tstr[200];
  150.     static int i, ret;
  151.     
  152.     get_format_time(tstr);
  153.     printf("hello %s: timer_proc2 is here./n", tstr);
  154.     if(i >= 5)
  155.     {
  156.         get_format_time(tstr);
  157.         ret = del_a_timer(hdl[2]);
  158.         printf("timer_proc2: %s del_a_timer::ret=%d/n", tstr, ret);
  159.     }
  160.     i++;
  161.     call_cnt++;
  162.     
  163.     return (1);
  164. }


  165. int main(void)
  166. {
  167.     char arg[50];
  168.     char tstr[200];
  169.     int ret;
  170.     
  171.     init_mul_timer();
  172.     hdl[0] = set_a_timer(2, timer_proc1, NULL, 0);
  173.     printf("hdl[0]=%d/n", hdl[0]);
  174.     hdl[1] = set_a_timer(3, timer_proc2, arg, 50);
  175.     printf("hdl[1]=%d/n", hdl[1]);
  176.     hdl[2] = set_a_timer(3, timer_proc2, arg, 101);
  177.     printf("hdl[1]=%d/n", hdl[2]);
  178.     while(1)
  179.     {
  180.         if(call_cnt >= 12)
  181.         {
  182.             get_format_time(tstr);
  183.             ret = destroy_mul_timer();
  184.             printf("main: %s destroy_mul_timer, ret=%d/n", tstr, ret);
  185.             call_cnt++;
  186.         }
  187.         if(call_cnt >= 20)
  188.         {
  189.             break;
  190.         }
  191.     }
  192.     
  193.     return 0;
  194. }

  195. #endif

3、缺陷
   i)新建定时器、遍历定时器和删除定时器(查找哪个定时器超时)时时间复杂度都为O(n)(n是定时器的个数);
   ii)适用环境是单线程环境,如要用于多线程,需添加同步操作。
   iii)程序中有些小bug,如对新建超时时间为0的定时器没有妥善的处理。

三、多定时器的改进版
1、思路
   改进定时器的实现,即是改善二种所指出的几个缺陷,如下是一个改进版,主要是将遍历超时时间的时间复杂度降为了O(1).
   改善思路:各定时器以一个链表的形式组织起来,除链表头定时器的超时时间是用绝对时间纪录的外,其它定时器的超时时间均用相对时间(即超时时间-前一个定时器的超时时间)纪录.
   注意,各定时器都是一次性的,当定时器的超时被处理后,定时器将被自动删除.另外如果将定时器的结点改为双向结构,可以将删除定时器的时间复杂度降为O(1).
2、数据结构
   每个定时器都有一个唯一的ID,这个ID是如下的结构体:



  1. typedef struct _timer_handle
  2. {
  3.         unsigned long ptr;
  4.         unsigned long entry_id;
  5. }*timer_handle_t;

  ptr纪录的是定时器结点的地址,entry_id则是一个自多定时器初始化后自增的id.ptr和entry_id一起组成定时器结点的key,一方面使得新建定时器时生成key的过程大为简化,另一方面使得删除定时器的时间复杂度降为O(1)(前提是定时器结点采用双向结构)。
   定时器结点的数据结构如下:


  1. /* timer entry */
  2. typedef struct _mul_timer_entry
  3. {
  4.     char is_use; /* 0, not; 1, yes */
  5.     struct _timer_handle handle;
  6.     unsigned int timeout;
  7.     unsigned int elapse; /* */
  8.     int (* timer_proc) (void *arg, unsigned int *arg_len); /* callback function */
  9.     void *arg;
  10.     unsigned int *arg_len;
  11.     struct _mul_timer_entry *etr_next;
  12. }mul_timer_entry_t;

其中的is_use是用来防止这样一种情况:用户在回调函数中调用kill_timer来删除定时器,这个时候kill_timer和遍历定时器中都有删除结点的操作,有可能将整个链表搞混乱。所以在调用用户的回调函数前先将is_use置1,在kill_timer中需检查is_use,只有在 is_use为0的情况下,才执行清理定时器结点的操作。
3、代码(windows版)
i)mul_timer.h

  1. /* This file provides an interface of multiple timers. it can't be used in multithreading environment.
  2.  * Author:bripengandre
  3.  * Date:2009-07-19
  4.  */

  5. #ifndef _MUL_TIMER_H_
  6. #define _MUL_TIMER_H_
  7. #include <windows.h>

  8. typedef struct _timer_handle
  9. {
  10.         unsigned long ptr;
  11.         unsigned long entry_id;
  12. }*timer_handle_t;

  13. /* timer entry */
  14. typedef struct _mul_timer_entry
  15. {
  16.     char is_use; /* 0, not; 1, yes */
  17.     struct _timer_handle handle;
  18.     unsigned int timeout;
  19.     unsigned int elapse; /* */
  20.     int (* timer_proc) (void *arg, unsigned int *arg_len); /* callback function */
  21.     void *arg;
  22.     unsigned int *arg_len;
  23.     struct _mul_timer_entry *etr_next;
  24. }mul_timer_entry_t;

  25. typedef struct _mul_timer_manage
  26. {
  27.     unsigned long entry_id;
  28.     unsigned int timer_cnt;
  29.     unsigned int time_unit;
  30.     struct _mul_timer_entry *etr_head;
  31.     UINT timer_id;
  32. };



  33. struct _mul_timer_manage *init_mul_timer(unsigned int time_unit);
  34. timer_handle_t set_timer(struct _mul_timer_manage *ptimer, unsigned int time_out, int (* timer_proc) (void *arg, unsigned int *arg_len), void *arg, unsigned int *arg_len);
  35. int kill_timer(struct _mul_timer_manage *ptimer, timer_handle_t hdl);
  36. int get_timeout_byhdl(struct _mul_timer_manage *ptimer, timer_handle_t hdl);
  37. int get_timeout_bytimeproc(struct _mul_timer_manage *ptimer, int (* timer_proc) (void *arg, unsigned int *arg_len));
  38. int release_mul_timer(struct _mul_timer_manage *ptimer);

  39. int is_valid_time_hdl(timer_handle_t hdl);

  40. #endif /* _MUL_TIMER_H_ */

ii)mul_timer.c

  1. #include "mul_timer.h"
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <time.h>


  5. void CALLBACK traverse_mul_timer(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2);
  6. static int print_mul_timer(struct _mul_timer_manage *ptimer);

  7. struct _mul_timer_manage *init_mul_timer(unsigned int time_unit)
  8. {
  9.     struct _mul_timer_manage *p;
  10.     
  11.     if( (p = malloc(sizeof(struct _mul_timer_manage))) == NULL)
  12.     {
  13.         return (NULL);
  14.     }
  15.     
  16.     p->etr_head = NULL;
  17.     p->timer_cnt = 0;
  18.     p->time_unit = time_unit;
  19.     p->entry_id = 0;
  20.     
  21.     p->timer_id = timeSetEvent(time_unit, 0, (LPTIMECALLBACK )traverse_mul_timer, (DWORD)p, TIME_PERIODIC);
  22.     
  23.     return(p);
  24. }


  25. timer_handle_t set_timer(struct _mul_timer_manage *ptimer, unsigned int time_out, int (* timer_proc) (void *arg, unsigned int *arg_len), void *arg, unsigned int *arg_len)
  26. {
  27.     struct _mul_timer_entry *p, *prev, *pnew;
  28.     
  29.     if(ptimer == NULL || time_out == 0)
  30.     {
  31.         return (NULL);
  32.     }
  33.     
  34.     
  35.     if( (pnew = malloc(sizeof(struct _mul_timer_entry))) == NULL)
  36.     {
  37.         return (NULL);
  38.     }
  39.     pnew->is_use = 0;
  40.     pnew->arg = arg;
  41.     pnew->arg_len = arg_len;
  42.     pnew->elapse = 0;
  43.     pnew->timer_proc = timer_proc;
  44.     
  45.     p = ptimer->etr_head;
  46.     prev = NULL;
  47.     while(p != NULL)
  48.     {
  49.         if(p->timeout < time_out) /* assume the latest time_proc has higher priority */
  50.         {
  51.             time_out = time_out-p->timeout;
  52.             prev = p;
  53.             p = p->etr_next;
  54.         }
  55.         else
  56.         {
  57.             p->timeout -= time_out;
  58.             break;
  59.         }
  60.     }
  61.     
  62.     pnew->timeout = time_out;
  63.     pnew->etr_next = p;
  64.     pnew->handle.ptr = (unsigned long )pnew;
  65.     pnew->handle.entry_id = ptimer->entry_id;
  66.     ptimer->entry_id++;

  67.     if(prev == NULL)
  68.     {
  69.         ptimer->etr_head = pnew;
  70.     }
  71.     else
  72.     {
  73.         prev->etr_next = pnew;
  74.     }
  75.     ptimer->timer_cnt++;
  76.     
  77.     return (&pnew->handle);
  78. }


  79. int kill_timer(struct _mul_timer_manage *ptimer, timer_handle_t hdl)
  80. {
  81.     struct _mul_timer_entry *p, *prev;
  82.     
  83.     if(ptimer == NULL)
  84.     {
  85.         return (0);
  86.     }
  87.     
  88.     
  89.     p = ptimer->etr_head;
  90.     prev = NULL;
  91.     while(p != NULL)
  92.     {
  93.         if(p->handle.ptr == hdl->ptr && p->handle.entry_id == hdl->entry_id)
  94.         {
  95.             break;
  96.         }

  97.         prev = p;
  98.         p = p->etr_next;
  99.     }
  100.     
  101.     /* no such timer or timer is in use, return 0 */
  102.     if(p == NULL || (p != NULL && p->is_use == 1))
  103.     {
  104.         return (0);
  105.     }
  106.     
  107.     /* has found the timer */
  108.     if(prev == NULL)
  109.     {
  110.         ptimer->etr_head = p->etr_next;
  111.     }
  112.     else
  113.     {
  114.         prev->etr_next = p->etr_next;
  115.     }
  116.     
  117.     /* revise timeout */
  118.     if(p->etr_next != NULL)
  119.     {
  120.         p->etr_next->timeout += p->timeout;
  121.     }
  122.     
  123.     /* delete the timer */
  124.     free(p);
  125.     p = NULL;
  126.     ptimer->timer_cnt--;
  127.     
  128.     return (1);
  129. }


  130. int get_timeout_byhdl(struct _mul_timer_manage *ptimer, timer_handle_t hdl)
  131. {
  132.     struct _mul_timer_entry *p;
  133.     unsigned int timeout;
  134.     
  135.     if(ptimer == NULL || (struct _mul_timer_entry *)(hdl) == NULL)
  136.     {
  137.         return (-1);
  138.     }
  139.     
  140.     
  141.     timeout = 0;
  142.     p = ptimer->etr_head;
  143.     while(p != NULL)
  144.     {
  145.      if(p->handle.ptr == hdl->ptr && p->handle.entry_id == hdl->entry_id)
  146.         {
  147.             break;
  148.         }

  149.         timeout += p->timeout;
  150.         p = p->etr_next;
  151.     }
  152.     
  153.     if(p == NULL)
  154.     {
  155.         return (-1);
  156.     }
  157.     else
  158.     {
  159.         return ((int)timeout+p->timeout);
  160.     }
  161.     
  162. }


  163. int get_timeout_bytimeproc(struct _mul_timer_manage *ptimer, int (* timer_proc) (void *arg, unsigned int *arg_len))
  164. {
  165.     struct _mul_timer_entry *p;
  166.     unsigned int timeout;
  167.     
  168.     if(ptimer == NULL || timer_proc == NULL)
  169.     {
  170.         return (-1);
  171.     }
  172.     
  173.     p = ptimer->etr_head;
  174.     while((p != NULL) && (p->timer_proc != timer_proc))
  175.     {
  176.         timeout += p->timeout;
  177.         p = p->etr_next;
  178.     }
  179.     
  180.     if(p == NULL)
  181.     {
  182.         return (-1);
  183.     }
  184.     else
  185.     {
  186.         return (timeout+p->timeout);
  187.     }
  188. }


  189. int release_mul_timer(struct _mul_timer_manage *ptimer)
  190. {
  191.     struct _mul_timer_entry *p, *ptmp;
  192.     
  193.     if(ptimer == NULL)
  194.     {
  195.         return (0);
  196.     }
  197.     
  198.     timeKillEvent(ptimer->timer_id);
  199.     /* delete all timers */
  200.     p = ptimer->etr_head;
  201.     while(p != NULL)
  202.     {
  203.         ptmp = p;
  204.         p = p->etr_next;
  205.         free(ptmp);
  206.     }
  207.     /* delete timer_manage */
  208.     free(ptimer);
  209.     ptimer = NULL;
  210.     
  211.     return (1);
  212. }

  213. int is_valid_time_hdl(timer_handle_t hdl)
  214. {
  215.     if(hdl == NULL)
  216.     {
  217.         return (0);
  218.     }
  219.     else
  220.     {
  221.         return (1);
  222.     }
  223. }


  224. void CALLBACK traverse_mul_timer(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
  225. {
  226.     struct _mul_timer_manage *ptimer;
  227.     struct _mul_timer_entry *p, *ptmp;
  228.     unsigned int timeout;
  229.     
  230.     ptimer = (struct _mul_timer_manage *)dwUser;
  231.     if(ptimer == NULL)
  232.     {
  233.         return;
  234.     }
  235.     
  236.     timeout = ptimer->time_unit;
  237.     p = ptimer->etr_head;
  238.     while(p != NULL)
  239.     {
  240.         if(p->timeout <= timeout)
  241.         {
  242.             p->is_use = 1;
  243.             p->timer_proc(p->arg, p->arg_len);
  244.             ptmp = p;
  245.             timeout -= p->timeout;
  246.             p = p->etr_next;
  247.             free(ptmp);
  248.             ptimer->etr_head = p;
  249.         }
  250.         else
  251.         {
  252.             p->timeout -= timeout;
  253.             p->elapse += timeout;
  254.             ptimer->etr_head = p;
  255.             break;
  256.         }
  257.     }
  258.     if(p == NULL)
  259.     {
  260.         ptimer->etr_head = NULL;
  261.     }
  262.     
  263.     return;
  264. }


  265. static int print_mul_timer(struct _mul_timer_manage *ptimer)
  266. {
  267.     struct _mul_timer_entry *p;
  268.     int i;
  269.     
  270.     if(ptimer == NULL)
  271.     {
  272.         return (0);
  273.     }
  274.     
  275.     printf("***************************mul_timer statistics start************************/n");
  276.     printf("this mul_timer's time_unit=%u, etr_head=%p and has %d timers:/n", ptimer->time_unit, ptimer->etr_head, ptimer->timer_cnt);
  277.     
  278.     p = ptimer->etr_head;
  279.     i = 0;
  280.     while(p != NULL)
  281.     {
  282.         printf("the %d timer: timeout=%u, elapse=%u, timer_proc=%p, arg=%p, arg_len=%p, etr_next=%p/n"
  283.             , i+1, p->timeout, p->elapse, p->timer_proc, p->arg, p->arg_len, p->etr_next);
  284.         p = p->etr_next;
  285.         i++;
  286.     }
  287.     printf("***************************mul_timer statistics end************************/n");
  288.     
  289.     return (1);
  290. }


  291. #define _MUL_TIMER_MAIN

  292. #ifdef _MUL_TIMER_MAIN

  293. static void get_format_time(char *tstr)
  294. {
  295.     time_t t;
  296.     
  297.     t = time(NULL);
  298.     strcpy(tstr, ctime(&t));
  299.     tstr[strlen(tstr)-1] = '/0';
  300.     
  301.     return;
  302. }

  303. timer_handle_t hdl[100];
  304. int call_cnt = 0;
  305. struct _mul_timer_manage *ptimer;

  306. int timer_proc1(void *arg, unsigned int *len)
  307. {
  308.     char tstr[200];
  309.     static int i, ret;
  310.     
  311.     get_format_time(tstr);
  312.     printf("call_cnt=%d, hello %s: timer_proc1 is here./n", call_cnt, tstr);
  313.     i++;
  314.     call_cnt++;
  315.     
  316.     
  317.     return (1);
  318. }

  319. int timer_proc2(void * arg, unsigned int *len)
  320. {
  321.     char tstr[200];
  322.     static int i, ret;
  323.     
  324.     get_format_time(tstr);
  325.     printf("call_cnt=%d, hello %s: timer_proc2 is here: arg = %s, len = %d./n", call_cnt, tstr, arg, *len);
  326.     i++;
  327.     call_cnt++;
  328.     
  329.     return (1);
  330. }


  331. int main(void)
  332. {
  333.     char arg[50] = "hello, multiple timers";
  334.     char tstr[200];
  335.     int ret;
  336.     int len = 50, i;
  337.     
  338.     ptimer = init_mul_timer(1000);
  339.     
  340.     for(i = 0; i < 10; i++)
  341.     {
  342.         hdl[i<<1] = set_timer(ptimer, 1000*(i+1), timer_proc1, NULL, NULL);
  343.         printf("hdl[0i<<1=%d, is_valid_hdl=%d/n", hdl[i<<1], is_valid_time_hdl(hdl[i<<1]));
  344.         hdl[(i<<1)+1] = set_timer(ptimer, 3000*(i+1), timer_proc2, arg, &len);
  345.         printf("hdl[i<<1+1]=%d, is_valid_hdl=%d/n", hdl[(i<<1)+1], is_valid_time_hdl(hdl[(i<<1)+1]));
  346.         print_mul_timer(ptimer);
  347.     }

  348.     ret = kill_timer(ptimer, hdl[17]);
  349.     printf("ret=kill_timer=%d/n", ret);
  350.     print_mul_timer(ptimer);
  351.     printf("hd[19]->timout=%d/n", get_timeout_byhdl(ptimer, hdl[19]));

  352.     while(1)
  353.     {
  354.         if(call_cnt == 15)
  355.         {
  356.             get_format_time(tstr);
  357.             ret = release_mul_timer(ptimer);
  358.             printf("call_cnt=%d, main: %s destroy_mul_timer, ret=%d/n", call_cnt, tstr, ret);
  359.             call_cnt++;
  360.         }
  361.     }
  362.     
  363.     return 0;
  364. }

  365. #endif

3、缺陷
i)新建定时器的时间复杂度为O(n),删除定时器的时间复杂度也为O(n)(简单地将定时器结点改为双向结构,可将复杂度降为O(1));
ii)不能用于多线程环境
四 、多定时器的工业级实现
 1、time wheelz算法
   以前的BSD内核以及现在的linux内核的实现与三中所用算法相似(未实证,只是据说),据说现在的BSD内核已采用了较好的time wheelz算法。
   time wheez算法的优点:
   i)将新建定时器的时间复杂度降近似为O(1)。它根据定时器的超时值,将新定时器散列到hash桶中;
   ii)遍历检查定时器的时间复杂度也近似为O(桶大小),如果散列均匀。
   iii)删除定时器的时间复杂度近似为O(1),通过hash算法或临时存储(空间换时间的算法)。
2、time wheelz的实现
   请参考文末给出的两个论文,惭愧得很,文章我也只是稍微瞄了下,以后有用得着的时候再深究吧。
五、参考文章
1、 Adam M. Costello and George Varghess, "Redesigning the BSD Callout and Timer Facilities". 1995.01,这篇文章实现了用time wheelz算法改善BSD内核的定时器算法,google一下,有免费下载;
2、George Varghess, Anthony Lauch, "Hashed and Hierarchical Timing Wheels: Efficient Data Structures for Implementing a Timer Facility". IEEE: 1997.12,这个看作者有没有提供免费下载了,否则是要从IEEE那里获取了~~
阅读(1608) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~