Timer事件
反应堆event_base包含了一个最小堆min_heap结构体的实例,以此维护注册到这个反应堆实例的定时器事件:
1.structevent_base {
2.//其他成员
3.structmin_heap timeheap;
4.};
回顾一下最小堆min_heap:
1.typedefstruct min_heap
2.{
3.//p指向一个动态分配的数组,数组元素是event指针.
4.structevent** p;
5.unsigned n, a;// n表示目前保存了多少元素,a表示p指向的内存能够存储event指针的个数
6.} min_heap_t;
可以看到,它包含一个连续的内存块用于存储定时器事件.针对min_heap的操作主要有:
1.staticinline int min_heap_push(min_heap_t* s, struct event* e);
2.staticinline structevent* min_heap_pop(min_heap_t* s);
其中,min_heap_push()用于插入节点,min_heap_pop()用于弹出节点.其内部逻辑很简单,不必描述了.
现在看看libevent处理定时器事件的例子:
01.staticvoid timeout_cb(intfd, short event, void *arg) {...}
02.
03.intmain (int argc, char **argv)
04.{
05.structevent timeout;
06.structtimeval tv;
07.
08.event_init();
09.
10.evtimer_set(&timeout, timeout_cb, &timeout);
11.
12.evutil_timerclear(&tv);
13.tv.tv_sec = 2;
14.event_add(&timeout, &tv);
15.
16.lasttime =time(NULL);
17.
18.event_dispatch();
19.}
首先,和上篇文章例子一样的,event_init()初始化一个event_base(反应堆实例),然后由evtimer_set()设置定时器事件的回调函数,接着event_add()把定时器事件加入反应堆实例中.最后进入event_dispatch()主循环.
在这里,evtimer_set定义如下:
1.#define evtimer_set(ev, cb, arg) event_set(ev, -1, 0, cb, arg)
至于event_set(),没有什么好说的,就是对一个event结构体做初始化罢了.
上一篇文章已经从I/O事件的角度介绍了event_add(),这里看看它是如何处理定时器事件的:
01.intevent_add(struct event *ev, const struct timeval *tv)
02.{
03.structevent_base *base = ev->ev_base;
04.
05.....//处理IO事件或者信号事件的逻辑.
06.
07.//如果tv不为0
08.if(tv != NULL)
09.{
10.event_queue_insert(base, ev, EVLIST_TIMEOUT);
11.}
12.}
可以看到,event_add()会把一个定时器事件压入到其对应的反应堆实例下的定时器最小堆timeheap中(&ev->base.timeheap).
回到event_dispatch(),它会调用event_base_loop(),此函数对定时器事件处理如下:
view sourceprint?
01.//事件主循环
02.int
03.event_base_loop(structevent_base *base, intflags)
04.{
05....//不必多虑的其他代码
06.
07.done = 0;
08.while(!done)
09.{
10.//检查heap中的timer events,将就绪的timer event从heap上删除,并插入到激活链表中,
11.//这意味着base->event_count_active会增加
12.timeout_process(base);
13.
14.//有就绪事件了
15.if(base->event_count_active)
16.{
17.//处理就绪事件吧.
18.event_process_active(base);
19.}
20.}
21.}
其中,timeout_process()会将已超时的定时器事件插入到反应堆实例下的已就绪事件队列中,接着由event_process_active()处理已就绪事件.event_process_active()代码在上一篇文章中已经介绍过了,这里看一下timeout_process():
01.
/时间到~~~
02.
//开始处理base里面的定时器堆里的事件鸟.
03.
//检查heap中的timer events,将就绪的timer event从heap上删除,并插入到激活链表中
04.
void
timeout_process(
struct
event_base *base)