libevne核心-event_base

半腔热情 提交于 2019-12-08 14:24:24

1.生成一个event_base

在使用其他的libevent函数之前,你必须要先分配一个event_base结构,event_base结构持有

event集合并且能判断那个event是活跃的。

如果event_base被设置为使用locking,那么它在多线程内访问是安全的。但是它的loop只能在

一个线程内执行。如果想要多个线程都能polling,就需要每个线程一个event_base结构。

每个event_base都有一个method(或者backend),用于判断event就绪。这些method有:

1.select

2.poll

3.epoll

3.kqueue

4.devpoll

5.evport

6.win32

你可以用环境变量来disable特定的backend,如果你想关闭kqueue,那么设置EVENT_NOKQUEUE环境

变量,或者使用函数event_config_avoid_method()

2.设置一个默认的event_base

event_base_new()分配并返回一个默认设置的event_base,如果出错,它返回NULL。

它会选择操作系统支持的最快的method最为自己的method。

接口:

#include<event2/event.h>

struct event_base* event_base_new(void);

3.设置一个复杂的event_base

如果你想要控制event_base的类型,就需要使用event_configevent_config是一个持有event_base

信息的结构。你可以使用event_base_new_with_config()函数并传递一个event_config结构作为参数

来生成你想要的event_base

接口:

struct event_config* event_config_new(void);
struct event_base* event_base_new_with_config(const struct event_config* cfg);
void event_config_free(struct event_config* cfg);

当你使用完毕,必须使用event_config_free去释放内存。

接口:

int event_config_avoid_method(struct event_config* cfg,const char* method);

enum event_method_feature{
    EV_FEATURE_ET = 0x01,
    EV_FEATURE_O1 = 0x02,
    EV_FEATURE_FDS = 0x04,
};
int event_config_require_feature(struct event_config* cfg,
                enum event_method_feature feature);

enum event_base_config_flag{
    EVENT_BASE_FLAG_NOBLOCK = 0x01,
    EVENT_BASE_FLAG_IGNORE_ENV = 0x02,
    EVENT_BASE_FLAG_STARTUP_IOCP = 0x04,
    EVENT_BASE_FLAG_NO_CACHE_TIME = 0x08,
    EVENT_BASE_FLAG_EPOLL_CHANGELIST  = 0x10,
    EVENT_BASE_FLAG_PRECISE_TIMER = 0x20,
};
int event_config_set_flags(struct event_config* cfg,
            enum event_base_config_flag flag);

调用event_config_avoid_method()来告知libevent避免使用name指定的method,调用event_config_require_feature()

来告知libevent不要使用不能提供feature集合的backend,调用event_config_set_flag()来告知

libevent在构造event_base时设置这些run-time flags。

event_config_feature()使用的feature值有:

  1. EV_FEATURE_ET: 要求backend method支持边缘触发(edge-triggered)IO。

  2. EV_FEATURE_O1: 要求backend method在添加、删除一个单一event,或者单一event变成active时,只有O(1)的复杂度。

  3. EVENT_FEATURE_FDS: 要求backend method支持任意类型的文件描述符。

event_config_set_flag()使用的flag有:

1.EVENT_BASE_FLAG_NOLOCK: 不要为event_base分配锁,设置这个选项可以为锁定和释放event_base

节省一些时间,但是在多线程中访问变得不安全。

2.EVENT_BASE_FLAG_IGNORE_ENV: 当检查可用的backend method时,不检查EVENT_* 环境变量,这会

导致在debug你的程序和libevent之间的交互时变得困难。

3.EVENT_BASE_FLAG_STARTUP_IOCP: 仅可在window中使用,这个flag让libevent在启动时就enable IOCP

dipatch logic,而不是在真正需要时才启动。

4.EVENT_BASE_FLAG_NO_CACHE_TIME: event loop 在执行完timeout calback后检查当前时间,而不是每次

都在准备好执行timeout callback检查当前时间。

5.EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST: 告知libent如果决定使用epoll backend,使用更快的changelist

backend是安全的。epoll-changelist能在文件描述符状态被改变时减少不必要的系统调用,但是它也会导

致触发内核bug,如果你给libent提供dup克隆文件描述符或者它的副本。

6.EVNET_BASE_FLAG_PRECISE_TIMER: 默认的,libevent总是尝试使用操作系统提供最快的可使用

time machanism。

接口:

int event_config_set_num_cpus_hint(struct event_config* cfg,int cpus);

仅在windows使用IOCP时可用,调用此函数以告知libent使用给定的cpu数。

接口:

int event_config_set_max_dispatch_interval(struct event_config* cfg,
                const struct timeval* max_interval,
                int max_callbacks,
                int min_priority);

这个函数通过限制在检查更高优先级事件之前,可以调用多少个低优先级事件回调,以防止优先级反转。

如果max_interval为non-null,event_loop在每次callbaack之后检查事件,并且重新扫描高优先级事件。

如果max_callbacks为非负数,event_loop在max_callbacks个回调被调用之后检查更多的事件。

示例:preferring 边缘触发

struct event_config *cfg;
struct event_base *base;
int i;

/* My program wants to use edge-triggered events if at all possible.  So
   I'll try to get a base twice: Once insisting on edge-triggered IO, and
   once not. */
for (i=0; i<2; ++i) {
    cfg = event_config_new();

    /* I don't like select. */
    event_config_avoid_method(cfg, "select");

    if (i == 0)
        event_config_require_features(cfg, EV_FEATURE_ET);

    base = event_base_new_with_config(cfg);
    event_config_free(cfg);
    if (base)
        break;

    /* If we get here, event_base_new_with_config() returned NULL.  If
       this is the first time around the loop, we'll try again without
       setting EV_FEATURE_ET.  If this is the second time around the
       loop, we'll give up. */
}

示例:避免优先级倒置

struct event_config *cfg;
struct event_base *base;

cfg = event_config_new();
if (!cfg)
   /* Handle error */;

/* I'm going to have events running at two priorities.  I expect that
   some of my priority-1 events are going to have pretty slow callbacks,
   so I don't want more than 100 msec to elapse (or 5 callbacks) before
   checking for priority-0 events. */
struct timeval msec_100 = { 0, 100*1000 };
event_config_set_max_dispatch_interval(cfg, &msec_100, 5, 1);

base = event_base_new_with_config(cfg);
if (!base)
   /* Handle error */;

event_base_priority_init(base, 2);

4.检查一个event_base的backend method

当你想要直到event_base中实际可用的feature或者那个method在被使用,使用下面接口:

接口:

const char** event_get_supported_methods(void);

这个函数返回一个指向method名的数组的指针,该数组的最后一个元素为NULL。

示例:

int i;
const char **methods = event_get_supported_methods();
printf("Starting Libevent %s.  Available methods are:\n",
    event_get_version());
for (i=0; methods[i] != NULL; ++i) {
    printf("    %s\n", methods[i]);
}

接口:

const char* event_base_get_method(const struct event_base *base);
enum event_method_feature event_base_get_features(const struct event_base* base);

event_base_get_method返回event_base实际使用method的名称,event_base_get_feature()

返回event_base支持的feature的bitmask.

示例:

struct event_base *base;
enum event_method_feature f;

base = event_base_new();
if (!base) {
    puts("Couldn't get an event_base!");
} else {
    printf("Using Libevent with backend method %s.",
        event_base_get_method(base));
    f = event_base_get_features(base);
    if ((f & EV_FEATURE_ET))
        printf("  Edge-triggered events are supported.");
    if ((f & EV_FEATURE_O1))
        printf("  O(1) event notification is supported.");
    if ((f & EV_FEATURE_FDS))
        printf("  All FD types are supported.");
    puts("");
}

5.析构一个event_base

接口:

void event_base_free(struct event_base* base);

该函数不会析构任何与event_base联系的event,或者关闭任何socket。

6.设置event_base的优先级

默认的,event_base只有一个优先级,但你可以使用:

接口:

int event_base_priority_init(struct event_base* base,int n_priorities);

该函数成功返回0,出错返回-1。

接口:

int event_base_get_npriorities(struct event_base* base);

获取event_base的优先级数量。

7.在fork()之后重初始化event_base

如果你的程序使用fork()或者相关的系统调用以开始一个新的进程,并且你想要继续使用event_base.

那么你需要重初始化它。

接口:

int event_reinit(struct event_base* base);

实例:

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); /*...*/
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!