程序员人生 网站导航

libevent学习四

栏目:框架设计时间:2015-02-06 08:30:42

构建event_base

在你开始使用任何Libevent前,你需要先创建1个或多个event_base。每一个event_base管理着1个event的集合,并可以检测出哪些event被激活了。如果event_base使用了锁,就能够在多线程中安全的访问它。但要注意它的主poll函数只能被单个线程运行。如果你想用多个线程运行IO迭代器,你需要为每一个线程分配1个event_base。

注:在以后的版本中,Libevent可能提供对跨线程event的支持。

每一个event_base都有1个“方法”或主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()会创建1个默许设置的event_base。它根据相应的环境变量,返回1个指向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()用来创建1个event_config。然后,调用其他的1些方法去告知它你想要的。最后通过event_base_new_with_config去创建1个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的时候去设置1些运行时标志。

1些用在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分配锁。设置这个选项可能为你节省1点花费在加锁,解锁上的时间,但是在多线程情况下,会变得不安全。

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”模式。如果同1个fd的状态在进入下1次循环前就被修改,epoll-changelist可以免没必要要的系统调用。但要注意的是,如果Libevent使用的fd被dup()函数克隆,那它可能会触发1个内核毛病。如果你没有使用epoll,它是不起作用的。你可以通过设定EVENT_EPOLL_USE_CHANGLIST环境变量去启用epoll-changelist。
EVENT_BASE_FLAG_PRECISE_TIMER:默许情况下,Libevent会尝试去使用系统提供的效力最高的计时器。如果有1个计时器虽然比较慢,但是有更高的精确度。这个flag会让Libevent去使用它。

接口

int event_config_set_num_cpus_hint(struct event_config *cfg, int cpus)
这个方法只在使用IOCP的Windows系统上有作用,固然在将来它也会被用在其他平台上。调用它用来告知event_base充分使用给定数量的CPU。注:这只是1个提议,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⑴ 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);


检查某个event_base的主函数
某些时候,你想肯定1个event_base的支持那些特性,或它使用的是哪一个主函数,你可以:

接口

const char **event_get_supported_methods(void);
它返回1个指向方法名的数组的指针。最后1个元素为NULL。

例:

int i; const char **methods = event_get_supported_methods(); printf("Starting Libevent %s. Available methods are: ", event_get_version()); for (i=0; methods[i] != NULL; ++i) { printf(" %s ", 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(""); }


释放event_base
当你结束使用event_base的时候,你可以通过调用event_base_free()释放它。

接口

void event_base_free(struct event_base *base);
注:这个方法其实不释放任何event_base所管理的events,也不会关闭它们的socket,或释放它们的指针。

设置event_base的优先级

Libevent支持在1个event_base中设置多个优先级。默许它只支持1个基本的优先级。你可以通过调用event_base_priority_init()来设置优先级的数量。

接口

int event_base_priority_init(struct event_base *base, int n_priorities);
它成功返回0,失败返回⑴。n_priorities是所设置的优先级的个数。它最小为1。可用的优先级是从0(优先级最高)到n_priorities⑴(优先级最低)。

它有个最大常量的限制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,失败返回⑴。

例:

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


------分隔线----------------------------
------分隔线----------------------------

最新技术推荐