摘 要:提出Linux用户空间下的一种高性能定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池" title="定时器池">定时器池的实现方法。主要基于时间轮、红黑树及Linux内核提供了一种利于管理的定时器句柄Timerfd。结合红黑树、位图、时间轮等技术,设计一种高性能级定时器池。池中定时器的粒度可达到40 ms,满足用户空间低延时的应用需求,同时又可以方便地管理一定数量的定时器。
关键词: 高性能; 定时器池; 定时器; 时间轮; 红黑树
定时器(timer)是Linux提供的一种定时服务的机制[1]。在使用定时器时,预先设置一个定时时间,并给定时时间到达时执行预先设定的任务。目前Linux系统本身提供了多种用户级定时器接口,其中精度较低的如Alarm函数,精度为秒级,能够满足一些定时精度低的应用场合。但由于同一进程中不能同时调用多个Alarm函数,因此应用场合有限。Setitimer克服不能重复使用的缺点,同时将精度提高到毫秒级,但是同一个进程中只能设置一个这种定时器。Timerfd是Linux为用户程序提供的另一个定时器接口,这个接口基于文件描述符,能够被用于select/poll的应用场景,其精度可以达到纳秒级,是用户空间高精度定时器的理想选择。本设计的定时器池基于时间轮原理,设定一个时间片大小作为时间间隔的基本单位,将时间轮分为固定时间片数,只需要一个Timerfd来管理该定时器池,设定超时时间间隔为时间片的大小,每次当超过一个时间片的时间时,系统将会通知定时器池的管理线程,管理线程做出相应的动作。综合以上优劣,本文提出一种定时器池的算法,用于管理大量定时器[2-3]。
1 设计原理以及工作流程
1.1 定时器池的结构
本定时器池选用Timerfd作为添加和删除定时器的接口,使用Linux提供的函数timerfd_settime来设定定时的间隔时间大小。本定时器池的时间间隔为一个时间片time_slot大小。设定之后,管理线程等待系统的信号通知,系统每隔一个时间片就给定时器池发送一个信号,当收到此信号时,管理线程轮询定时器池,查看池中是否有超时的定时器,若有则按用户需求执行相关动作。定时器池的结构如图1所示。
当用户想要添加或者删除定时器时,可直接调用添加或者删除函数,定时器池内部的管理线程将自动处理用户的需求,将用户所需的定时器加到定时器池相应的时间片链表中统一管理。定时器池中定时器的组织形式如图2所示。
图2中模拟了时间轮原理:用一个结构体来保存一个时间片,以时间片作为定时器粒度的最小单位,以及该时间片下定时器的数量,同时该结构体包含该时间片下的定时器链表的链表头部,用来链接双向链表,链表选用Linux内核所采用的嵌入式双向链表结构,如式(1)所示:
struct list_head{
struct list_head *next, *prev} (1)
1.2 定时器的添加
用户根据其需求在定时器池中加入定时器,插入定时器之前所要做的工作有:
(1)计算定时器插入时间片,每个定时器的插入时间片计算公式为:
timer->slot =(pool->cur_slot+timer->interval/
pool->time_slot )% pool->slot_num; (2)
式(2)中timer为要插入的定时器结构,其中的timer->slot为定时器插入的时间片,pool->cur_slot为定时器池当前所轮询到的时间片,time->interval为所要添加的定时器的定时时间间隔,pool->time_slot为每个时间片的长度,pool->slot_num为定时器池的时间片总数。
(2)计算定时器的时间轮数,每个定时器的时间轮数计算公式为:
timer->round=timer->interval/
(pool->time_slot*pool->slot_num) (3)
其中的timer->round为该定时器的时间轮数,通过式(3)得出定时器的时间轮数。
(3)用户在添加定时器到定时器池中时,需要指定定时器的超时时间,以及超时时间到达后所需要执行的函数。同时,必须指定该定时器是一次性定时还是周期性定时,以便管理线程删除或者重新添加该定时器。
1.3 定时器池的工作流程
创建并初始化定时器池,此时内存中保存着一个定时器池动态管理单元,用户通过相应接口请求定时器池按其要求增加或者删除定时器。定时器池工作流程如图3所示。工作时,内部的定时器管理线程一直监听用户请求,同时管理线程等待系统的信号通知,当有信号通知到来时,管理线程轮询定时器池,查看池中已有的定时器池中是否有超时的定时器,若有则按照用户指定的动作来执行。原因是:(1)可直接调用函数,这种方法的优点是不用产生线程的开销;缺点是将占用定时器的时间,并且若该函数执行时间较长,将严重影响定时器的性能。(2)产生线程来执行该任务,这种方法的优点是不占用定时器池的时间,缺点是需要产生线程开销[4]。
管理线程还将检查定时器的属性,即该定时器是一次性定时还是周期性定时,如果是一次性定时,当定时器超时后,管理线程将该定时器从链表结构中移除;如果是周期性定时,当超时后,管理线程首先将定时器从链表结构中移除,然后计算该定时器池再次插入的时间片以及时间轮数,得到以上数据后,按照时间片数将定时器重新插入到相应的链表中,实现用户的需求。
1.4 定时器的删除
当定时器时间到时,若为一次性定时,当定时器超时后,管理线程自动地将定时器从链表中移除,释放相关内存。但是,当用户因为某种需要在中途删除未超时的一次性定时器或者删除周期性定时器时,此时需要调用定时器删除函数来删除定时器。但是从定时器链表中寻找特定的定时器并非一件容易的事情,本文采用基于红黑树的形式,相应的结构体设计如下:
typedef int key_t; (4)
typedef void* data_t; (5)
struct rb_node_t {
struct rb_node_t *left, *right, *parent;
key_t key; data_t data;
color_t color;} (6)
在添加定时器时,会给每个定时器分配一个唯一的id来标记定时器,该id存放在一张位图表中,将以O(1)的速度索取未用的id或者存储到期回收的定时器id。将该定时器id作为红黑树的键值key,将指向定时器的内存结构指针作为红黑树的data 数据。管理线程同时维护红黑树。当需要非正常删除某个定时器时,通过定时器的id找出其在红黑树中的位置,获取定时器结构在内存中所在位置的指针,以便从定时器链表中删除该定时器。红黑树的查找性能保持在O(logn),从而快速找出定时器指针所在红黑树的单元。
2 定时器池算法的实现
采用面向对象的思想,头文件.h中只包含用户可以查看到基本的结构,.c文件中包含实际的定时器池的内部数据结构,这样可以避免用户操作结构体中的数据成员[7]。
2.1 定时器池的函数接口 还没注册? 现在免费注册,您即可: ?阅读所有技术文章及下载网站资料; ?定期获得业界最新资讯及设计实例; ?拥有个人空间参与网站及客户活动; ?撰写博客与业界朋友交流分享经验; 已经注册? 登录阅览全部精彩内容 用户名: 密码: