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.
    else
        Wait 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           0x20

typedef 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
//事件不需要是未决的,激活事件也不会让他成为未决的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值