5.1 运行循环
一旦有了一个已经注册了某些事件的 event_base(关于如何创建和注册事件请看下一节 ), 就需要让 libevent 等待事件并且通知事件的发生。
#define EVLOOP_ONCE 0x01#define EVLOOP_NONBLOCK 0x02#define EVLOOP_NO_EXIT_ON_EMPTY 0x04int event_base_loop(struct event_base *base, int flags);
默认情况下,event_base_loop()函数运行 event_base 直到其中没有已经注册的事件为止。执行循环的时候 ,函数重复地检查是否有任何已经注册的事件被触发 (比如说,读事件 的文件描述符已经就绪,可以读取了;或者超时事件的超时时间即将到达 )。如果有事件被触发,函数标记被触发的事件为 “激活的”,并且执行这些事件。
在 flags 参数中设置一个或者多个标志就可以改变 event_base_loop()的行为。如果设置了 EVLOOP_ONCE ,循环将等待某些事件成为激活的 ,执行激活的事件直到没有更多的事件可以执行,然会返回。如果设置了 EVLOOP_NONBLOCK,循环不会等待事件被触发: 循环将仅仅检测是否有事件已经就绪,可以立即触发,如果有,则执行事件的回调。
完成工作后,如果正常退出, event_base_loop()返回0;如果因为后端中的某些未处理 错误而退出,则返回 -1。
为帮助理解,这里给出 event_base_loop()的算法概要:
while (any events are registered with the loop,or EVLOOP_NO_EXIT_ON_EMPTY was set) {if (EVLOOP_NONBLOCK was set, or any events are already active)If any registered events have triggered, mark them active.elseWait until at least one event has triggered, and mark it active.for (p = 0; p < n_priorities; ++p) {if (any event with priority of p is active) {Run all active events with priority of p.break; /* Do not run any events of a less important priority */}}if (EVLOOP_ONCE was set or EVLOOP_NONBLOCK was set)break;}
为方便起见,也可以调用
int event_base_dispatch(struct event_base *base);
event_base_dispatch ()等同于没有设置标志的 event_base_loop ( )。所以, event_base_dispatch ()将一直运行,直到没有已经注册的事件了,或者调用 了 event_base_loopbreak()或者 event_base_loopexit()为止。
这些函数定义在
5.2 停止循环
如果想在移除所有已注册的事件之前停止活动的事件循环,可以调用两个稍有不同的函数 。
int event_base_loopexit(struct event_base *base,const struct timeval *tv);int event_base_loopbreak(struct event_base *base);
event_base_loopexit()让 event_base 在给定时间之后停止循环。如果 tv 参数为 NULL, event_base 会立即停止循环,没有延时。
如果 event_base 当前正在执行任何激活事件的回调,则回调会继续运行,直到运行完所有激活事件的回调之才退出。
event_base_loopbreak ()让 event_base 立即退出循环。它与 event_base_loopexit (base,NULL)的不同在于,如果 event_base 当前正在执行激活事件的回调 ,它将在执行完当前正在处理的事件后立即退出。
注意 event_base_loopexit(base,NULL) 和 event_base_loopbreak(base) 在事件循环没有运行时的行为不同:前者安排下一次事件循环在下一轮回调完成后立即停止(就好像带 EVLOOP_ONCE 标志调用一样);后者却仅仅停止当前正在运行的循环,如果事件循环没 有运行,则没有任何效果。
这两个函数都在成功时返回 0,失败时返回 -1。
实例:
#include <event2/event.h>/* Here's a callback function that calls loopbreak */void cb(int sock, short what, void *arg){struct event_base *base = arg;event_base_loopbreak(base);}void main_loop(struct event_base *base, evutil_socket_t watchdog_fd){struct event *watchdog_event;/* Construct a new event to trigger whenever there are any bytes toread from a watchdog socket. When that happens, we'll call thecb function, which will make the loop exit immediately withoutrunning any other active events at all.*/watchdog_event = event_new(base, watchdog_fd, EV_READ, cb, base);event_add(watchdog_event, NULL);event_base_dispatch(base);}
实例2:执行事件循环10秒,然后退出
#include <event2/event.h>void run_base_with_ticks(struct event_base *base){struct timeval ten_sec;ten_sec.tv_sec = 10;ten_sec.tv_usec = 0;/* Now we run the event_base for a series of 10-second intervals, printing"Tick" after each. For a much better way to implement a 10-secondtimer, see the section below about persistent timer events. */while (1) {/* This schedules an exit ten seconds from now. */event_base_loopexit(base, &ten_sec);event_base_dispatch(base);puts("Tick");}}
有时候需要知道对 event_base_dispatch()或者 event_base_loop()的调用是正常退出 的,还是因为调用 event_base_loopexit()或者 event_base_break()而退出的。可以调 用下述函数来确定是否调用了 loopexit 或者 break函数。
int event_base_got_exit(struct event_base *base);int event_base_got_break(struct event_base *base);
这两个函数分别会在循环是因为调用 event_base_loopexit()或者 event_base_break()而退出的时候返回 true,否则返回 false。下次启动事件循环的时候,这些值会被重设。
这些函数声明在
event_break_loopexit()函数首次在 libevent 1.0c 版本 中实现;
event_break_loopbreak()首次在 libevent 1.4.3版本中实现。
5.3 转储event_base的状态
为帮助调试程序(或者调试 libevent),有时候可能需要加入到 event_base 的事件及其状态 的完整列表。调用 event_base_dump_events()可以将这个列表输出到指定的文件中。
void event_base_dump_events(struct event_base *base, FILE *f);
这个列表是人可读的,未来版本的 libevent 将会改变其格式。
