SIP协议中的用于超市重传或其他用途的定时器(timer)很多,令人头大,很久以前就想到如何实现这些定时器,以前用C coding的时候,就是简单地sleep一下来延时。今天仔细分析了pjsip协议栈中定时器的实现源代码。灰常兴奋地看了... pjsip也是借鉴别人的实现方法,这在其官网上,作者如是说。 pjsip中管理定时器的数据结构是堆,是采用小顶堆来实现的,该堆为一棵完全二叉树,该完全二叉树采用顺序结构(即是数组)实现。 对于每一个定时器,pjsip中用一个定时器实体结构体来描述,该实体结构体如下:
注释已经很清楚了,不细说啦...... 另一个很重要的实体结构是延时的时间结构体,其包括时间的s和ms两个域:
上述说了小顶堆,以及定时器实体,还有时间结构,那么究竟怎么实现定时功能呢? 不说大家也猜得到,我们必须提供某种机制来判断定时器是否timeout,怎么判断?pjsip中采用轮询的方式,不断轮询定时器堆(定时器实体构成一个定时器小顶堆)根元素,来判断是否超时的。 首先,pj_timer_heap_create()创建定时器堆; 然后,pj_timer_heap_schedule()来调度定时器,也就是插入到定时器堆中,该函数实现堆的基本操作,一旦一个定时器结构体加入堆,就开始计时,此时,该加入的定时器结构体记录了入堆的当前时刻加上延时时间,也就是将来的定时到的某个时刻; 然后,pj_timer_heap_poll()在某线程或者主线程中不断轮询定时器堆的根元素,并且获取轮询时候的当前时刻,用它来和根元素的超时刻比较,如果根元素的记录时刻小于当前时刻,那么该定时器超时,然后将其从堆中删掉,并调用回调函数,进行超时操作。 上述的定时精度不能说十分准确,单基本够用。 后记: 其实定时器的实现原理很简单,就是创建一种机制来判断当前时刻某定时器是否超时。这个过程是个循环的过程。曾经用c语言采用sleep的方式实现定时,使用函数指针来传回调函数为用户提供API,但是精度远不如上述方式。 (chenjily) |