event_base01

来源:互联网 发布:jquery 二维数组 push 编辑:程序博客网 时间:2024/06/16 05:37

出处:http://m.blog.csdn.net/huangjh2017/article/details/78045299

1. 简介

在使用libevent函数之前需要分配一个或者多个event_base结构体。每个event_base结构体持有一个事件集合,可以检查以确认哪个事件是激活的。如果设置event_base使用锁,则可以安全的在多个线程中访问它。然而,其事件循环只能运行在一个线程中(Reactor模型)。如果需要多个线程检查IO,则需要为每个线程使用一个event_base。
每个event_base都有一种用于检测哪种事件已经准备就绪的方法(后端)。这些方法实际上是封装了不同操作系统下的slect、poll、epoll、kqueue、devpoll、evport和win32。就以Linux为例:Linux中的支持slect、poll、epoll三种IO多路复用。

2. 建立默认的event_base

通过调用event_base_new()函数分配并且返回一个新的具有默认设置的event_base。
//event.c  //创建一个默认的event_basestruct event_base *event_base_new(void){struct event_base *base = NULL;struct event_config *cfg = event_config_new();//创建了一个默认的event_configif (cfg) {base = event_base_new_with_config(cfg);//利用默认的event_config创建一个默认的event_baseevent_config_free(cfg);//释放掉分配的event_config}return base;}
创建一个默认的event_base非常的简单,只需要调用event_base_new即可;如果想要对event_base有更多的控制就需要使用event_config结构。event_config是一个容纳event_base配置信息的不透明结构体。我们只要将对应的配置信息event_config传递给event_base_new_with_config,该函数返回我们需要的event_base。

3. 建立复杂的event_base

3.1 event_config 结构体

struct event_config结构是libevent内部使用的结构:用于描述一个event_base的配置信息。event_config结构用函数event_config_new()进行分配,对于分配的这个结构我们可以对其调用其他相关设置函数对其设置。event_config结构如下所示:
/** Internal structure: describes the configuration we want for an event_base * that we're about to allocate. */struct event_config {TAILQ_HEAD(event_configq, event_config_entry) entries;int n_cpus_hint;struct timeval max_dispatch_interval;int max_dispatch_callbacks;int limit_callbacks_after_prio;enum event_method_feature require_features;enum event_base_config_flag flags;};
  • entries:将宏展开其实就是一个队列的头,这个队列用于存放event_config_entry对象,每个event_config_entry对象包含一个避免使用指定的后端方法(比如select、poll等)。当我们调用event_config_avoid_method函数的时候,就分配一个event_config_entry对象,并初始化其成员,然后将其插入到队列的尾部。如果需要屏蔽某个后端方法则需要添加该项。
  • n_cpus_hint:CPU数。
  • max_dispatch_interval:用于event_base检查新事件的间隔。默认情况下,event_base在检查新事件之前,有多少最高优先级的激活事件就执行多少这样的事件,这样做的好处是吞吐量大,但是很有可能出现优先级反转(如果多个低优先级发生,高优先级后发生,而event_base一直执行低优先级事件,高优先级无法及时执行,导致优先级反转)。这个选项正是为了解决这个问题,如果我们设置了这个选项,那么event_base将每次在执行完回调之后,检查上一次检查到现在为止事件间隔是否超过了max_dispatch_interval。这个函数能使高优先级的事件响应更快,但是会稍微降低吞吐量。
  • max_dispatch_callbacks:两次检测新事件之间,不会执行超过max_dispatch_callbacks个回调。
  • limit_callbacks_after_prio:表示优先级低于limit_callbacks_after_prio的将不会执行上面的2个检查。如果设置为0,则对每个优先级进行检查。
  • require_features:后台的方法特性。关于这些后台的方法特性与具体的操作系统有关(比如Linux上支持select、poll和epoll)。下面会具体讲解。
  • flags:event_base的标志 。支持的标志参考枚举类型event_method_feature。下面会具体讲解。
我们能通过调用event_config_set_num_cpus_hint函数进行CPU数的设置;

通过调用event_config_set_max_dispatch_interval来设置max_dispatch_interval,max_dispatch_callbacks和limit_callbacks_after_prio,如果不想设置max_interval可传入NULL,如果不需要设置max_dispatch_callbacks,可设置为-1,如果limit_callbacks_after_prio设置为0,则对每个优先级都进行上述2中检查,否则,只对大于等于limit_callbacks_after_prio的优先级事件进行上述2种检查;

通过调用event_config_require_features对后台方法特性进行设置;

通过event_config_set_flag函数对event_base的工作模式进行设置

。这些接口非常的简单,仅仅是设置event_config结构,这边就不详细列出来了。

3.2 event_method_feature

枚举类型event_method_feature表示支持的后台方法特性。某些特性与具体的后台方法或操作系统有关。通过调用event_config_require_features让libevent不使用不能提供所需要的后台方法。
  • EV_FEATURE_ET:要求支持边缘触发的后端。
  • EV_FEATURE_O1:要求添加、删除单个事件,或者确认哪个事件激活的操作是O(1)复杂度的。
  • EV_FEATURE_FDS:要求支持任意的文件描述符,而不仅仅是支持套接字。
  • EV_FEATURE_EARLY_CLOSE:要求支持EV_CLOSE 检查连接的关闭,而不是读完所有数据。

3.3 event_base_config_flag

枚举类型event_base_config_flag表示支持的标志。
  • EVENT_BASE_FLAG_NOLOCK:设置此标志,表示不要为event_base分配锁,能使得event_base节约加锁和解锁的时间,但是在多个线程中访问event_base是非线程安全的。
  • EVENT_BASE_FLAG_IGNORE_ENV:选择使用的后端时,不要检测EVENT_ *环境变量。
  • EVENT_BASE_FLAG_STARTUP_IOCP:仅Window使用,让libevent在启动时就启用IOCP分发逻辑。
  • EVENT_BASE_FLAG_NO_CACHE_TIME:不是在事件循环每次准备执行超时回调时检测当前时间,而是在每次超时回调后进行检测。
  • EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST:告诉libevent,如果决定使用epoll 后端,可以安全地使用更快的基于changelist 的后端。
  • EVENT_BASE_FLAG_PRECISE_TIMER:通常情况下,libevent使用的时间和超时时间是使用最快的单调计数器,如果设置此标志,我们将使用更为精准的单调时间。

4. 设置event_base的优先级

libevent支持为事件设置多个有优先级。然而,event_base默认只支持单个优先级。可调用event_base_priority_init()设置event_base的优先级数目。event_base中新事件的优先级将会是0(最高)-n_priorities-1(最低)。

5. 建立一个默认的event_base

建立一个默认的event_base非常的简单。
#include <stdio.h>#include <string.h>#include <event2/event-config.h>#include <event2/event.h> //cc -I/usr/local/include -o test main.cpp -L/usr/local/lib -leventint main(void){struct event_base *base;//建立默认的event_baseebase = event_base_new();const char **ppSupportMethod = event_get_supported_methods();for (int i = 0; ppSupportMethod[i] != NULL; ++i)printf("supported method : %s\r\n", ppSupportMethod[i]);const char *pCurrMethod = event_base_get_method(base);if (pCurrMethod != NULL)printf("Current method is %s\r\n", pCurrMethod);//do something...event_base_dispatch(base);event_base_free(base);return 0;}
在Linux上编译运行
supported method : epollsupported method : pollsupported method : selectCurrent method is epoll