本文主要是介绍libevent使用(二) ----- event_base 和 event,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
关于event_base
如果设置event_base使用锁,则可以安全的在多线程这使用它。
然而,其 事件循环则只能运行在一个线程中,如果需要用多个线程检测IO,则需要为每个线程使用一个event_base。建立默认的event_base
struct event_base *event_base_new(void)
//函数分配并返回一个新的具有默认设置的event_base。函数会检测环境变量,返回一个到event_base的指针
//发生错误则返回NULL。
//选择I/O复用方法时,也会选择系统支持的最快的方法。
检查event_base的后端方法
有时我们可能需要检查event_base支持哪些特性,以及使用的哪种IO复用
const char **event_get_support_methods(void)
//此函数返回一个数组的指针,数组内容是当前版本libevent支持的I/O复用方法的名字
//数组最后一个元素是NULL
const char *event_base_get_method(const struct event_base *)
//此函数返回event_base真正使用的IO复用方法
enum event_method_feature event_base_get_features(const struct event_base *)
//此函数则返回支持的特征掩码, 可通过与某特征相与判断是否支持该特征
释放申请的event_base
void event_base_free(struct event_base*)
//要注意的是这个函数只是释放event_base, 不释放相关的event等
设置event_base的 优先级
int event_base_priority_init(struct event_base *, int n_priorities)
//event_base默认只支持单个优先级, 而支持为事件设置多个优先级,即调用此函数设置优先级数目
//此函数修改的是支持的优先级数目。每个新的事件的可用优先级从0(最高)到 n_priorities-1(最低)
//要注意的是。要在任何事件激活之前调用此函数
//新事件的优先级被初始化为 n_priorities/2
在fork之后重新初始化event_base
int event_reinit(struct event_base *)
Example:
struct event_base *base = event_base_new();/* ... add some events to the event_base ... */if (fork()) {/* In parent */continue_running_parent(base); /*...*/
} else {/* In child */event_reinit(base);continue_running_child(base); /*...*/
}
当我们拥有了一个event_base,和几个注册了的event之后,我们希望开始执行循环,等待事件、发出提醒。
int event_base_loop(struct event_base *base, int flags)
//#define EVLOOP_ONCE 0x01
// 函数会等待某些事件成为"active", 运行他们直到没有事件可运行,然后调用return
//#define EVLOOP_NONBLOCK 0x02
// 函数不会等待事件成为"active", 只是检查是否有事件已准备好,没有就返回,有就执行回调函数
//#define EVLOOP_NO_EXIT_ON_EMPTY 0x04
// 默认情况下,只要有已注册事件存在,函数就一直运行event_base,直到没有任何注册事件了就退出。我们也可以修改这种默认行为,也就是使用这个标识。使用此标识后,循环会继续,直到某线程调用 event_base_loopbreak或是 event_base_exit 。继续执行期间也可通过其他线程给此base添加事件。
//执行循环时,函数重复检查是否有任何已注册事件被激活了(读就绪?超时?)。如果有事件被触发,函数就标记事件为"active"的,并且开始处理他们
方便理解:
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;
}
函数 event_base_dispatch(struct base *) 与 event_base_loop(...)的默认方式类似
停止循环
int event_base_loopexit(struct event_base *base, struct timeval *tv)
//即使有注册时间也退出。如果tv为空,立刻执行。然而如果正在为"active"的句柄调用回调函数,那么会执行完所有"active"的回调函数才结束
int event_base_loopbreak(struct event_base *)
//如果有正在执行的句柄回调函数,那么执行完这个句柄函数后就结束,而不是像event_base_loopexit函数一样会把所有回调函数执行完
还要注意的是event_base_loopexit(base,NULL)和event_base_loopbreak(base)在事件循环没有运行时的行为不同:
前者安排下一次事件循环在下一轮回调完成后立即停止; 后者仅仅停止当前正在运行的循环
关于event
构建事件对象
#define EV_TIMEOUT 0x01(这个标识在event_new里面是被忽略的,可以在 event_add 的时候设置)
#define EV_READ 0x02
#define EV_WRITE 0x04
#define EV_SIGNAL 0x08
#define EV_PERSIST 0x10
#define EV_ET 0x20typedef void (*event_callback_fn)(evutil_socket_t, short, void *);
struct event *event_new(struct event_base *base, evutil_socket_t fd, short what, event_callback_fn cb, void *arg);
void event_free(struct event *event);
关于 事件的持久性(即 EV_PERSIST)
默认情况下,每当未决事件成为激活的,事件将在其回调函数被执行前成为非未决的。如果想让事件再次成为为未决的,可以在回调函数中再次对其调用event_add
然而如果设置了此标识,事件就是持久的 。这意味着即使其回调被激活,事件还是保持为未决的状态。如果想在回调中让事件成为非未决的,可以对其调用 event_del()
因此,每次执行事件回调的时候,持久事件的超时值会被复位。
如果具有 EV_READ | EV_PERSISIT标识,且超时为5秒,事件将在以下情况成为active的:
1、可读
2、从最后一次激活开始,过去了5秒
要注意的是,每个进程任何时刻只能有一个event_base可以监听信号,如果同时向两个event_base添加信号事件,即使是不同的信号,只有一个base会收到信号
让事件未决和非未决
int event_add(struct event *ev, const struct timeval *tv);
int event_del(struct event *ev);
//要注意的是,如果你在某事件成为"active"且在调用回调函数之前使用event_del移除该事件,那么回调函数是不会被执行的
移除事件定时器
int event_remove_timer(struct event *ev);
//使用此函数可以在不移除事件的情况下一处超时时间
//如果是单纯的超时时间,那么相当于event_del函数
事件的优先级
当许多事件同时发生时,回调函数的执行顺序是未定义的,可以通过priority来指定某些事件比某些事件重要
int event_priority_set(struct event *, int priority);
//此优先级最大值为设置的event_base的优先级减去1
检查事件的状态
有时候我们可能需要判断一个事件是否已经添加进base,或想知道事件代表什么
int event_pending(const struct event *ev, short what, struct timeval *tv_out);
//The event_pending function determines whether the given event is pending or active. If it is, and any of the flags EV_READ, EV_WRITE, EV_SIGNAL, and EV_TIMEOUT are set in the what argument, the function returns all of the flags that the event is currently pending or active on. If tv_out is provided, and EV_TIMEOUT is set in what, and the event is currently pending or active on a timeout, then tv_out is set to hold the time when the event’s timeout will expire.#define event_get_signal(ev) /* ... */
evutil_socket_t event_get_fd(const struct event *ev);
struct event_base *event_get_base(const struct event *ev);
short event_get_events(const struct event *ev);
event_callback_fn event_get_callback(const struct event *ev);
void *event_get_callback_arg(const struct event *ev);
int event_get_priority(const struct event *ev);
void event_get_assignment(const struct event *event,struct event_base **base_out,evutil_socket_t *fd_out,short *events_out,event_callback_fn *callback_out,void **arg_out);
//The event_get_assignment() function copies all of the assigned fields of the event into the provided pointers. If any of the pointers is NULL, it is ignored.
给出使用实例:
#include <event2/event.h>
#include <stdio.h>/* Change the callback and callback_arg of 'ev', which must not be* pending. */
int replace_callback(struct event *ev, event_callback_fn new_callback,void *new_callback_arg)
{struct event_base *base;evutil_socket_t fd;short events;int pending;//函数返回事件是否是未决的pending = event_pending(ev, EV_READ|EV_WRITE|EV_SIGNAL|EV_TIMEOUT,NULL);
//如果是未决的,那我们此时不要操作(未决即当前事件挂在base上等待事件发生)if (pending) {/* We want to catch this here so that we do not re-assign a* pending event. That would be very very bad. */fprintf(stderr,"Error! replace_callback called on a pending event!\n");return -1;}//非未决,那么复制所有为事件分配的字段到提供的指针中event_get_assignment(ev, &base, &fd, &events,NULL /* ignore old callback */ ,NULL /* ignore old callback argument */);//重新为此事件指定回调函数和参数event_assign(ev, base, fd, events, new_callback, new_callback_arg);return 0;
}
配置 一次性触发事件
int event_base_once(struct event_base *, evutil_socket_t, short,void (*)(evutil_socket_t, short, void *), void *, const struct timeval *);
//此函数类似 event_new, 但是会在回调函数后内部释放event结构
//不能删除或者手动激活使用此函数插入的事件。如果希望能取消事件,那么使用 event_new 或 event_assign
手动激活事件
void event_active(struct event *ev, int what, short ncalls);
//此函数使事件被激活,且带有标识what
//事件不需要是未决的,激活事件也不会让他成为未决的
这篇关于libevent使用(二) ----- event_base 和 event的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!