构建event_base
在你开始使用任何Libevent前,你需要先创建一个或多个event_base。每个event_base管理着一个event的集合,并可以检测出哪些event被激活了。如果event_base使用了锁,就可以在多线程中安全的访问它。但要注意它的主poll函数只能被单个线程运行。如果你想用多个线程运行IO迭代器,你需要为每个线程分配一个event_base。
注:在以后的版本中,Libevent可能提供对跨线程event的支持。
每个event_base都有一个“方法”或主IO函数,用来确定哪些event已经被准备好。其中包括:
1. select
2. poll
3. epoll
4. kqueue
5. devpoll
6. evport
7. win32
使用者可以通过环境变量来禁用某个指定的主函数。如果你想去关掉kqueue函数,可以设置EVENT_NOKQUEUE这个环境变量等。如果你想在程序内部关掉,可以看下面对event_config_avoid_method的介绍:
设定默认的event_base
函数event_base_new()会创建一个默认设置的event_base。它根据相应的环境变量,返回一个指向event_base的指针。如果错误返回NULL。
默认它会自动选择系统所支持的最快的主函数。
接口
struct event_base *event_base_new(void);对于大多数程序,默认的设置就已经满足你的需求了。
定制自己的event_base
如果你想定制自己的event_base,你需要使用到event_config。event_config是个不对外开放的结构体。它保存着你对event_base偏好设定的相关信息。你可以通过传入event_config到event_base_new_with_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_new()用来创建一个event_config。然后,调用其他的一些方法去告诉它你想要的。最后通过event_base_new_with_config去创建一个event_base。创建后,通过event_config_free()来释放event_config。
接口
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_features(struct event_config *cfg, enum event_method_feature feature); enum event_base_config_flag { EVENT_BASE_FLAG_NOLOCK = 0x01, EVENT_BASE_FLAG_IGNORE_ENV = 0x02, EVENT_BASE_FLAG_STARTUP_IOCP = 0x04, EVENT_BASE_FLAG_NO_CACHE_TIME = 0x08, EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST = 0x10, EVENT_BASE_FLAG_PRECISE_TIMER = 0x20 }; int event_config_set_flag(struct event_config *cfg, enum event_base_config_flag flag);event_config_avoid_method用来告诉Libevent不要使用某个主函数。event_config_require_feature()用来告诉Libevent不要使用那些不支持feature所指定功能的主函数。event_config_set_flag()用来告诉Libevent在构建event_base的时候去设置一些运行时标志。
一些用在event_config_require_features的feature有:
EV_FEATURE_ET:要求主函数支持edge-triggered。(边缘模式)
EV_FEATURE_O1:要求主函数增加,删除event或某个event被激活的算法复杂度都是O(1)。
EV_FEATURE_FDS:要求主函数可以处理任意的文件描述符,而不仅仅是socket。
event_config_set_flag使用到的值有:
EVENT_BASE_FLAG_NOLOCK:不给event_base分配锁。设置这个选项可能为你节省一点花费在加锁,解锁上的时间,但是在多线程情况下,会变得不安全。
EVENT_BASE_FLAG_IGNORE_ENV:当选择使用哪个主函数时,不检查EVENT_*的环境变量。使用前要想清楚,因为它会让你在调试你的程序时,变得困难。
EVENT_BASE_FLAG_STARTUP_IOCP:只用在Windows上,在启动时就启用必要的IOCP逻辑调度。而不是按需。
EVENT_BASE_FLAG_NO_CACHE_TIME:不是在事件循环每次准备执行超时回调时检测当前时间,而是在每次超时回调后进行检测。注意,这会消耗更多的CPU时间。
EVENT_BASE_FLAG_EPOLL_USE_CHANGLIST:告诉Libevent,如果使用的主函数是epoll,使用更高效的“changelist”模式。如果同一个fd的状态在进入下一次循环前就被修改,epoll-changelist可以避免不必要的系统调用。但要注意的是,如果Libevent使用的fd被dup()函数克隆,那它可能会触发一个内核错误。如果你没有使用epoll,它是不起作用的。你可以通过设定EVENT_EPOLL_USE_CHANGLIST环境变量去启用epoll-changelist。
EVENT_BASE_FLAG_PRECISE_TIMER:默认情况下,Libevent会尝试去使用系统提供的效率最高的计时器。如果有一个计时器虽然比较慢,但是有更高的精确度。这个flag会让Libevent去使用它。
接口
int event_config_set_num_cpus_hint(struct event_config *cfg, int cpus)这个方法只在使用IOCP的Windows系统上有作用,当然在将来它也会被用在其他平台上。调用它用来告诉event_base充分使用给定数量的CPU。注:这只是一个提议,event_base可能会使用多于或少于你所给定的值。
int event_config_set_max_dispatch_interval(struct event_config *cfg, const struct timeval *max_interval, int max_callbacks, int min_priority);这个方法用来避免优先级反转。它是通过限制在检查高优先级event前,最多允许可被调用的低优先级event的数量来达到目的。如果max_interval非空,事件循环在每次回调后都会检查时间。如果超过max_interval指定的时间,就会重新扫描高优先级的events。如果max_callbacks非负,在max_callbacks调用被调用后,时间循环会继续检查更多的events。这些规则适用于任何高于min_priority的event。
例子:避免优先级反转
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);
接口
const char **event_get_supported_methods(void);它返回一个指向方法名的数组的指针。最后一个元素为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里面的主函数名字。event_base_get_features()函数它所支持的feature的按位与。
例:
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(""); }
接口
void event_base_free(struct event_base *base);注:这个方法并不释放任何event_base所管理的events,也不会关闭它们的socket,或释放它们的指针。
Libevent支持在一个event_base中设置多个优先级。默认它只支持一个基本的优先级。你可以通过调用event_base_priority_init()来设置优先级的数量。
接口
int event_base_priority_init(struct event_base *base, int n_priorities);它成功返回0,失败返回-1。n_priorities是所设置的优先级的个数。它最小为1。可用的优先级是从0(优先级最高)到n_priorities-1(优先级最低)。
它有个最大常量的限制EVENT_MAX_PRIORITIES。
注:这个方法必须在任何events被激活前被调用。最好在创建event_base后就调用它。
查看当前的event_base支持多少个优先级。可用调用:
接口
int event_base_get_npriorities(struct event_base *base);默认情况下,所有新的event被分配的优先级会被初始化为当前event_base的n_priorities/2。
fork()后重新初始化event_base
在调用fork()后,event相关的数据可能变脏。所以,如果你想在fork后的进程中继续使用event_base,你需要去重新初始化它。
接口
int event_reinit(struct event_base *base);这个方法成功返回0,失败返回-1。
例:
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); /*...*/ }
原文地址:http://blog.csdn.net/huanzai2/article/details/43026009