一、概述
libevent提供了高性能定时器的功能,方便执行延迟回调逻辑。
二、基本实现原理
在添加事件监听的时候,可以不指定fd和监听的事件,指定超时的时间,实现定时器功能。
定时器的底层实现包含两个部分:
- 最小堆:按事件的超时时间构造,超时时间最早的在堆顶。
- 通用超时队列:这个可以个性化设置每个队列的超时时间,添加事件时时间相同的放到同一个队列里,在最小堆里只添加一个队列首部的事件到最小堆。能避免大量事件都放到最小堆,导致最小堆添加、删除时性能变差的问题。
三、最小堆实现
最小堆的实现采用了典型的数组来维护,当数组元素满时,扩容数组,调整最小堆。
四、公共超时队列
1、用户可以自定义每个公共超时队列的超时时间,每个超时队列加入时时间的超时时间相同,这样保证了同一队列里的时间按加入队列时的时间超时。这样避免了在最小堆里维护大量的事件,只需在最小堆里加入一个超时事件即可。
2、公共超时队列的结构定义如下:
struct common_timeout_list {
struct event_list events; //事件列表
struct timeval duration; //duration表示加入到这个队列里时,都是duration的超时时间
struct event timeout_event; //每个common_timout_list,都会在超时最小堆里放一个超时事件,等timeout_event超时时,检查events里的哪些事件超时,并再往最小堆里加入一个超时事件。
struct event_base *base; //所属的event_base
};
3、具体的实现原理如下图:
每个队列是一个双向链表
五、定时器使用样例
struct event timeout;
struct timeval tv;
struct event_base *base;
int flags = 0; //0表示只执行一次,EV_PERSIST表示定时器超时后继续等待超时
/* Initalize the event library */
base = event_base_new();
/* Initalize one event */
event_assign(&timeout, base, -1, flags, timeout_cb, (void*) &timeout);
evutil_timerclear(&tv);
tv.tv_sec = 2;
event_add(&timeout, &tv);
evutil_gettimeofday(&lasttime, NULL);
event_base_dispatch(base);