event_loop
一旦我们有一些事件注册在一个event_base上后,我们自然想让libevent提醒我们。
//接口
#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);
默认情况下,这个event_base_loop函数会返回一个event_base,直到没有更多的时间注册在上面。在这个函数的循环中,会重复的去检查是否有哪个已经注册的事件已经激活了,一旦有激活的,就会把时间标为激活态,然后去处理。
我们也可以通过修改参数来改变Libevent的行为。
如果EVLOOP_ONCE被设置,那循环就会等事件激活然后处理,直到没有更多事件去处理了就返回。(就是边跑边等待的形式过一遍事件)
如果EVLOOP_NONBLOCK被设置,那循环就不会等待事件去激活,只会立马检查是否有任何事件已经激活了,然后去处理这些事件(就是跑但是不等待的形式过一遍)
一般情况下,这个循环会在没有中断和激活事件的情况下立即退出。但是我们也可以通过设置EVLOOP_NO_EXIT_ON_EMPTY标签一直循环,这样我们就可以在线程里去添加事件,直到发生错误或者调用函数event_base_loopbreak()或者event_base_loopexit()
event_base_loop()会正常情况下返回0,返回-1是有未处理的错误,返回1是没有更多激活事件。
while(如果事件已经注册||EVLOOP_NO_EXIT_ON_EMPTY){
if(EVLOOP_NONBLOCK,或者任何事件已经激活)
标志激活事件
else
等待直到最近的一个事件被激活
for(p = 0;p<n_priorities(优先级数量);++p)
{
if(任何此n优先级的事件激活)
{
运行所有此优先级激活的事件的回调函数
break;//不再运行任何低于此优先度的事件
}
}
if(EVLOOP_ONCE || EVLOOP_NONBLOCK)
break;
}
更方便的做法是,可以调用:
int event_base_dispatch(struct event_base* base);
此函数没有参数,会一直循环直到没有任何注册的事件或者event_base_loopbreak()或者event_base_loopexit()被调用
中止循环
如果我们想要一个正在运行的loop在所有的事件都被移除去之前停止,我们有两种简单的函数
int event_base_loopexit(struct event_base* base,const struct timeval* tv);
int event_base_loopbreak(struct event_base* base);
返回0成功,1失败
event_base_loopexit让一个event_base在给定时间后停止,如果不给时间就立马停止。如果event_base当前正在调用一个事件的回调函数,会等待全部的回调函数完成后再停止。(就是如果有激活事件的话,会调用所有事件的回调函数后再退出)
event_base_loopbreak让一个event_base立马停止,并且如果正在调用一个事件的回调函数,只会执行当前这一个事件的回调函数然后马上退出(只执行这一个的回调函数)
例子
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;
watchdog_event = event_new(base,watchdog_fd,EV_READ,cb,base);
event_add(watchdog_event,NULL);
event_base_dispatch(base);
}
#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;
while(1)
{
event_base_loopexit(base,&ten_sec);
event_base_dispatch(base);
puts("Tick");
}
}
有时候我们想知道event_base_loopexit()和event_base_break()是否被调用了,那么我们可以用下面两个函数
int event_base_got_exit(struct event_base* base);
int event_base_got_break(struct event_base* base);
一般情况下,Libevent检查事件然后调用最高优先级的激活事件群的回调函数,然后再去见检查事件。有时我们想跳出循环在当前一个事件回调已经完成后就再去检查事件,可以用这个函数
int event_base_loopcontinue(struct event_base* );
若当前没有调用任何一个回调函数的话就没有什么用。
检查内时间缓存
在一个回调函数中,我们可以得到Libevent自从执行这轮回调函数后的当前时间
int event_base_gettimeofday_cached(struct event_base* base, struct timeval* tv_out);
获得event_base 状态
void event_base_dump_events(struct event_base* base,FILE* f);
可以向f文件里输出所有当前base所有events的状态
在一个event_base里的所有event里运行一个函数
typedef int (*event_base_foreach_event_cb)(const struct event_base* , const struct event* ,void* );
int event_base_foreach_event(struct event_base* base,event_base_foreach_event_cb fn , void* arg);