参考博客:https://blog.csdn.net/windeal3203/article/details/52772233
1.event 状态
event:主要分为三种状态及转换:initialized、pending、active
- 关联base=>initialized状态
- event_add=>pending状态
- 触发事件,调用回调=>active状态
- event_del=>非pendding状态(可以理解为初始化状态)
- active状态(persistent属性)=>pending状态
- active状态(不含persistent属性)=>非pendding状态(可以理解为初始化状态)
2.event 使用流程
- 初始化事件event_new 、event_assign
- 注册事件 event_add
- 监听事件 event_base_dispatch
- 删除事件 event_del
- 释放事件 event_free
3.初始化event
对于已经在event_base中处于“挂起”状态的event,永远不要调用event_assign。这样做会导致极为难以诊断的错误。如果event已经初始化,并且处于“挂起”状态,那么在调用event_assign之前应该先调用event_del。*
//申请内存创建event ,内部使用event_assign赋值
struct event *event_new(struct event_base *, evutil_socket_t, short, event_callback_fn, void *);
//只是对event赋值,不申请内存。只能在event非pending or非active 才能操作,否则不安全
int event_assign(struct event *, struct event_base *, evutil_socket_t, short, event_callback_fn, void *);
//释放event,如果event处于pending or active,将会事先使其变为 non-pending and non-active,然后释放
void event_free(struct event *);
event 事件类型:
#define EV_TIMEOUT 0x01 /*定时事件*/
#define EV_READ 0x02 /*I/O事件*/
#define EV_WRITE 0x04 /*I/O事件*/
#define EV_SIGNAL 0x08 /*信号*/
#define EV_PERSIST 0x10 /*永久事件 */
#define EV_ET 0x20 /*边沿触发*/
EV_PERSIST 属性:
默认情况下,当一个“挂起”的event变为“激活”时(要么是因为fd准备好读或写,要么是超时时间到),
那么在它的回调函数执行之前,它就会变为“非挂起”状态。因此,如果希望再次使event变为“挂起”状态,可以在回调函数内
部再次调用event_add函数。
如果event设置了EV_PERSIST标志,那么event就是“持久”的。这意味着event在回调函数激活的时候,依然保持“挂起”
状态。如果希望在回调函数中将event变为“非挂起”状态,则可以调用event_del函数。
当event的回调函数运行时,“持久”event的超时时间就会被重置。因此,如果某个event标志为EV_READ|EV_PERSIST,
并且将超时时间设置为5秒,则该event在下面的条件发生时,会变为“激活”:当该socket准备好读时; 距离上次event变为
激活状态后,又过了5秒钟.
4.注册事件
int event_add(struct event *ev, const struct timeval *tv);
如果是一个(non-pending)未注册ev
,调用event_add
函数会注册该事件(变为pending状态)。如果是一个(pending)注册过的ev
,调用该函数会在tv时间后重新注册该事件。成功返回0,失败返回-1。
5.监听事件
int event_base_dispatch(struct event_base *base);
内部调用的event_base_loop,
//@param: flags
//等待IO事件
#define EVLOOP_ONCE 0x01
//非阻塞,直接返回
#define EVLOOP_NONBLOCK 0x02
//其他的线程中添加事件
#define EVLOOP_NO_EXIT_ON_EMPTY 0x04
int event_base_loop(struct event_base *base, int flags);
如果需要退出loop:
//延迟tv时间后,停止event loop
int event_base_loopexit(struct event_base *base, const struct timeval *tv);
//立刻停止,等同于tv = NULL
int event_base_loopbreak(struct event_base *base);
//获取退出方式
int event_base_got_exit(struct event_base *base);
int event_base_got_break(struct event_base *base);
6.其他event事件
- 查找正在运行的事件(event_base_get_running_event)
- 设置事件执行一次(event_base_once)
- 激活事件(event_active)
event_base
信息和状态写入文件(event_base_dump_events)
7、创建一个可以将自身作为回调函数参数的的event
//该函数返回一个“魔术”指针,使得event_new创建一个本身就能作为回调函数参数的event。
void*event_self_cbarg();
NOTE:当前版本的Libevent,对于大多数的后端方法来说,同一时间,每个进程仅能有一个event_base可以用来监听信号。如果一次向两个event_base添加event,即使是不同的信号,也仅仅会只有一个event_base可以接收到信号。对于kqueue来说,不存在这样的限制。