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); /*...*/
}