PJSIP 协议栈中定时器的实现详解

SIP协议中的用于超市重传或其他用途的定时器(timer)很多,令人头大,很久以前就想到如何实现这些定时器,以前用C coding的时候,就是简单地sleep一下来延时。今天仔细分析了pjsip协议栈中定时器的实现源代码。灰常兴奋地看了…

pjsip也是借鉴别人的实现方法,这在其官网上,作者如是说。

pjsip中管理定时器的数据结构是堆,是采用小顶堆来实现的,该堆为一棵完全二叉树,该完全二叉树采用顺序结构(即是数组)实现。

对于每一个定时器,pjsip中用一个定时器实体结构体来描述,该实体结构体如下:

/**
* This structure represents an entry to the timer.
*/
struct pj_timer_entry
{
    /** 
     * User data to be associated with this entry. 
     * Applications normally will put the instance of object that
     * owns the timer entry in this field.
     */
    void *user_data;
    /** 
     * Arbitrary ID assigned by the user/owner of this entry. 
     * Applications can use this ID to distinguish multiple
     * timer entries that share the same callback and user_data.
     */
    int id;
    /** 
     * Callback to be called when the timer expires. 
     */
    pj_timer_heap_callback *cb;
    /** 
     * Internal unique timer ID, which is assigned by the timer heap. 
     * Application should not touch this ID.
     */
    pj_timer_id_t _timer_id;
    /** 
     * The future time when the timer expires, which the value is updated
     * by timer heap when the timer is scheduled.
     */
    pj_time_val _timer_value;
};

注释已经很清楚了,不细说啦…

另一个很重要的实体结构是延时的时间结构体,其包括时间的s和ms两个域:

/**
* Representation of time value in this library.
* This type can be used to represent either an interval or a specific time
* or date. 
*/
typedef struct pj_time_val
{
    /** The seconds part of the time. */
    long    sec;
    /** The miliseconds fraction of the time. */
    long    msec;
} pj_time_val;

上述说了小顶堆,以及定时器实体,还有时间结构,那么究竟怎么实现定时功能呢?

不说大家也猜得到,我们必须提供某种机制来判断定时器是否timeout,怎么判断?pjsip中采用轮询的方式,不断轮询定时器堆(定时器实体构成一个定时器小顶堆)根元素,来判断是否超时的。

1、首先,pj_timer_heap_create()创建定时器堆;

2、然后,pj_timer_heap_schedule()来调度定时器,也就是插入到定时器堆中,该函数实现堆的基本操作,一旦一个定时器结构体加入堆,就开始计时,此时,该加入的定时器结构体记录了入堆的当前时刻加上延时时间,也就是将来的定时到的某个时刻;

3、然后,pj_timer_heap_poll()在某线程或者主线程中不断轮询定时器堆的根元素,并且获取轮询时候的当前时刻,用它来和根元素的超时刻比较,如果根元素的记录时刻小于当前时刻,那么该定时器超时,然后将其从堆中删掉,并调用回调函数,进行超时操作。
上述的定时精度不能说十分准确,单基本够用。

后记:
  
其实定时器的实现原理很简单,就是创建一种机制来判断当前时刻某定时器是否超时。这个过程是个循环的过程。曾经用c语言采用sleep的方式实现定时,使用函数指针来传回调函数为用户提供API,但是精度远不如上述方式。

文章目录
|