码迷,mamicode.com
首页 > 其他好文 > 详细

libevent学习四

时间:2015-01-22 23:25:34      阅读:412      评论:0      收藏:0      [点我收藏+]

标签:libevent   c   

构建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);


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

接口

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("");
}


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

接口

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

设置event_base的优先级

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


libevent学习四

标签:libevent   c   

原文地址:http://blog.csdn.net/huanzai2/article/details/43026009

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!