pjlib系列之定时器timer

pjlib的定时器简介

pjlib定时器是从ACE网络库移植过来的。实现在timer.h和timer.c,定时器的原理是有个将来的超时时间,这个时间就是现在时间加上定时器时长。

pjlib定时器使用

1、pj_timer_heap_create()创建定时器堆;
2、pj_timer_heap_schedule()来调度定时器,也就是插入到定时器堆中,该函数实现堆的基本操作,一旦一个定时器结构体加入堆,就开始计时,此时,该加入的定时器结构体记录了入堆的当前时刻加上延时时间,也就是将来的定时到的某个时刻;
3、pj_timer_heap_poll()在某线程或者主线程中不断轮询定时器堆的根元素,并且获取轮询时候的当前时刻,用它来和根元素的超时刻比较,如果根元素的记录时刻小于当前时刻,那么该定时器超时,然后将其从堆中删掉,并调用回调函数,进行超时操作

定时器结构体

定时器堆使用完全二叉树来管理定时器节点,其中heap变量是个节点二级指针,或者说指针数组,timer_ids是定时器id数组,timer_ids_freelist这个变量一直看不明白,为什么要取反。

/**
 * The implementation of timer heap.
 */
struct pj_timer_heap_t
{
    /** Pool from which the timer heap resize will get the storage from */
    pj_pool_t *pool;

    /** Maximum size of the heap. */
    pj_size_t max_size;

    /** Current size of the heap. */
    pj_size_t cur_size;

    /** Max timed out entries to process per poll. */
    unsigned max_entries_per_poll;

    /** Lock object. */
    pj_lock_t *lock;

    /** Autodelete lock. */
    pj_bool_t auto_delete_lock;

    /**
     * Current contents of the Heap, which is organized as a "heap" of
     * pj_timer_entry *'s.  In this context, a heap is a "partially
     * ordered, almost complete" binary tree, which is stored in an
     * array.
     */
    pj_timer_entry **heap;

    /**
     * An array of "pointers" that allows each pj_timer_entry in the
     * <heap_> to be located in O(1) time.  Basically, <timer_id_[i]>
     * contains the slot in the <heap_> array where an pj_timer_entry
     * with timer id <i> resides.  Thus, the timer id passed back from
     * <schedule_entry> is really an slot into the <timer_ids> array.  The
     * <timer_ids_> array serves two purposes: negative values are
     * treated as "pointers" for the <freelist_>, whereas positive
     * values are treated as "pointers" into the <heap_> array.
     */
    pj_timer_id_t *timer_ids;

    /**
     * "Pointer" to the first element in the freelist contained within
     * the <timer_ids_> array, which is organized as a stack.
     */
    pj_timer_id_t timer_ids_freelist;

    /** Callback to be called when a timer expires. */
    pj_timer_heap_callback *callback;

};

pj_timer_heap_create( pj_pool_t *pool, pj_size_t size, pj_timer_heap_t **p_heap)

申请size个定时器节点的定时器堆,会申请heap和timer_ids的内存空间,timer_ids的值设为1~size。

定时器节点

/**
 * This structure represents an entry to the timer.
 */
typedef 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;

    /**
     * Internal: the group lock used by this entry, set when
     * pj_timer_heap_schedule_w_lock() is used.
     */
    pj_grp_lock_t *_grp_lock;

#if PJ_TIMER_DEBUG
    const char	*src_file;
    int		 src_line;
#endif
} pj_timer_entry;

应用程序要自己创建pj_timer_entry对象,并设置定时器超时的回调函数,其它下划线开头的变量由内部设置。调用

pj_timer_heap_schedule( pj_timer_heap_t *ht,
                         pj_timer_entry *entry, 
                         const pj_time_val *delay)

就可以添加节点并启动定时器,其中entry应用程序自己创建,delay定时器时长,此函数内部会设置将来超时时间点,也就是entry中的_timer_value。先使用pj_gettickcount获取当前时间,再加上delay,就是将来时间。

PJ_DEF(pj_status_t) pj_timer_heap_schedule( pj_timer_heap_t *ht,
                                            pj_timer_entry *entry,
                                            const pj_time_val *delay)
{
    return schedule_w_grp_lock(ht, entry, delay, PJ_FALSE, 1, NULL);
}

static pj_status_t schedule_w_grp_lock(pj_timer_heap_t *ht,
                                       pj_timer_entry *entry,
                                       const pj_time_val *delay,
                                       pj_bool_t set_id,
                                       int id_val,
                                       pj_grp_lock_t *grp_lock)
{
 ....
    pj_gettickcount(&expires);
    PJ_TIME_VAL_ADD(expires, *delay);
    
    lock_timer_heap(ht);
    status = schedule_entry(ht, entry, &expires);
....

    return status;
}

static pj_status_t schedule_entry( pj_timer_heap_t *ht,
				   pj_timer_entry *entry, 
				   const pj_time_val *future_time )
{
    if (ht->cur_size < ht->max_size)
    {
	// Obtain the next unique sequence number.
	// Set the entry
	entry->_timer_id = pop_freelist(ht);
	entry->_timer_value = *future_time;
	insert_node( ht, entry);
	return 0;
    }
    else
	return -1;
}

至于定时器节点使用顺序存储完全二叉树的细节,就不展开,对timer_ids_freelist这个取反的变量不是很明白,二叉树的原理见一篇文章。深入学习二叉树

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值