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_config
,event_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值有:
EV_FEATURE_ET: 要求backend method支持边缘触发(edge-triggered)IO。
EV_FEATURE_O1: 要求backend method在添加、删除一个单一event,或者单一event变成active时,只有O(1)的复杂度。
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); /*...*/ }