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这个取反的变量不是很明白,二叉树的原理见一篇文章。深入学习二叉树