定时器的设计与时间轮算法

      定时器是很多程序都需要使用到的功能。
      现代操作系统有一个很重要的功能——进程切换,执行一个进程一半的时候跑去执行另一个进程。这是怎么做到的呢?
      就是由可编程硬件定时器发出信号(操作系统启动的时候设置),触发了操作系统注册的处理函数,在这个处理函数里把进程切换掉。

      硬件定时器是很珍贵的,我们基本上都是使用软件定时器。软件定时器说白了就是一个线程一直跑,看到注册的时间到了,就调用相应的回调函数。
      用c++描述软件定时器设计如下:
class TimeoutHandler // 使用接口的方式而不是boost::function,一方面是出于效率考虑,另一方面是这样便于理解
{
public:
      virtual ~TimeoutHandler(){}
      virtual void onTimeout() = 0;
};
class TimerMonitor
{
      int setTimer(int inteval, boost::shared_ptr<TimeoutHandler> handler); // 为何用智能指针?这种回调类的都很怕回调的时候对象被析构,智能指针是最简单解决办法
      void stopTimer(int timer_id);                                                                                // 删除,根据setTimer返回的timer_id进行删除,函数返回后保证不会再调用handler->onTimeout()
      void run(int check_inteval);                                                                                  // 以设置好的检测周期开始监控线程
    void stop();                                                                                                                 // 停止监控线程
};
      那具体如何实现TimerMonitor呢?
      最简单低效的做法就是维持一个数组/非排序列表:定时器线程一直跑,检测超时时轮询所有设置的时间,如果超过了就执行相应回调函数。这种算法每次检测要遍历所有设置的时间,无疑是低效的0(n)。插入O(1)删除O(n)。
      稍微高级的做法就是使用排序链表,最前面就是最近要到期的,检测超时时不需要轮询,只需要看看头几个结点即可(可视为O(1))。插入和删除O(n)。
      之前我知道的比较好的方法是最小堆,检测超时时也是O(1),插入0(lgn),删除O(n)——注意如果不引入其他数据结构的情况下只能通过遍历找到timer_id对应结点。
      今天刚知道的:Timing-Wheel时间轮算法,参考http://www.ibm.com/developerworks/cn/linux/l-cn-timers/。我感觉这个算法是很聪明的算法,水表的例子也非常好。我一开始看时间轮算法以为是类似TRIE的算法,后面又以为是多级Hash算法,但其实都似是而非。
      Timing Wheels的本质有点像水表:高维度一单位等于低维度的一圈。
      举个例子来说明吧,假设总共有两个维度,每个维度三个槽。
第一维:
      slot 1-1 :链表,放置在0间隔后过期的handler
      slot 1-2 :链表,放置在1间隔后过期的handler
      slot 1-3 :链表,放置在2间隔后过期的handler
第二维:
      slot 2-1 :链表,放置3-4-5间隔后过期的handler
      slot 2-2 :链表,放置6-7-8间隔后过期的handler
      slot 2-3 :链表,放置9-10-11间隔后过期的handler
      注意slot1-1,slot2-1 并不是固定的,而是由这一维度的当前指向位置决定的,可以把每一个维度当做一个循环队列。步进的时候就是最低维+1,但这个+1可能会导致进位甚至连环进位。
      假设有一个2*2*2的时间轮,步进时顺序是这样 0-0-0(初始) -> 1-0-0 -> 0-1-0(进位) -> 1-1-0 -> 0-0-1(连环进位))
      发生进位的时候要把高纬度那个槽里的handler抓来处理,如果时间到了就触发,还没到就塞进低维度的槽中。还举3*3的例子,当触发slot2-1的时候,所有3的定时器触发,4的塞到slot1-2,5的就塞到slot1-3。
      算法思想大抵是如此吧。等我哪天有空了再写代码嘿嘿。
     
      过了n天:终于动手实现了,http://blog.sina.com.cn/s/blog_48d4cf2d0100ql2b.html。


定时器的设计与时间轮算法
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值