在使用Libevent函数之前,需要分配一个或多个event_base结构。每一个event_base都持有一个events的集合,并且可以检测那些events是激活的。

如果设置event_base可以使用锁,那event_base是可以安全的在多线程环境中使用,但是,只能在单个的线程中进行event_base的loop。如果希望在多线程中进行IO轮询,那就需要每个线程都有一个event_base。(未来版本的Libevent可能会支持多线程支持event_base的loop)

每一个event_base都会有一个“后台方法”,用来检测哪一个events准备好了。主要包含下列方法:select、poll、epoll、kqueue、devpoll、evport、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);

它会挑选操作系统支持的最快的后台方法。对于大多数程序来说,使用这个接口基本上就足够了。该接口在<event2/event.h>中声明。

二:设置复杂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_base,可以通过event_config_new来分配新的event_config结构。然后调用其他函数,根据需要设置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使用任何无法提供一组特性的后端方法。调用event_config_set_flag(),可以在创建event_base时,设置一些运行时标志。

event_config_require_features支持的特性有:

EV_FEATURE_ET:需要支持边沿触发的后端方法

EV_FEATURE_O1:需要这样的后端方法,它的添加、删除event,或者确定哪个event变为激活等操作,都是O(1)的。

EV_FEATURE_FDS:需要可以支持任意文件描述符类型的后台方法,而不仅仅支持socket。

event_config_set_flag()支持的选项有:

EVENT_BASE_FLAG_NOLOCK:不为event_base分配锁。尽管这样做可以节省一点在event_base上加锁和解锁的时间,但是这会导致多线程环境下,无法安全的使用event_base。

EVENT_BASE_FLAG_IGNORE_ENV:在挑选使用哪个后台方法时,不检查EVENT_*环境变量,使用该标志之前要仔细考虑,因为他使得调试应用程序和Libevent之间的交互变得困难。

EVENT_BASE_FLAG_STARTUP_IOCP:仅用于Windows,该标志使得Libevent在启动时就使能必要的IOCP调度逻辑,而不是按需使能。

EVENT_BASE_FLAG_NO_CACHE_TIME:不是每次event loop准备运行超时回调函数时,检测当前时间,而是每次调用超时回调函数之后在检测。这样做会消耗额外的CPU,所以要小心。

EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST:告诉Libevent,如果使用的是epoll后端方法,那可以安全的使用基于changelist的更快的后端方法。如果在调用后端调度函数的中间,同样的描述符的状态多次改变的话,epoll-changelist可以避免不必要的系统调用。但是如果传递给Libevent的描述符fd是dup复制而来的话,那么会触发一个内核bug。该标志只有在使用epoll后端时有效。设置EVENT_EPOLL_USE_CHANGELIST环境变量,同样可以开启epoll-changelist选项。

EVENT_BASE_FLAG_PRECISE_TIMER:默认情况下,Libevent使用系统提供的最快的定时机制,如果存在较慢的定时机制,但是它可以提供更精细的定时精度,那么该标志可以使Libevent使用这种定时机制。如果操作系统没有这样的定时机制的话,则该标志是无效的。

上述操作event_config的函数在成功是返回0,失败是返回-1.

注意:设置event_config请求操作系统没有提供的后台方法是很容易的。比如,对于Libevent2.0.1-alpha来说,Windows没有O(1)的后端方法,而且Linux也不能提供EV_FEATURE_FDS和
EV_FEATURE_O1的后端方法。如果配置的Libevent无法满足的话,那么event_base_new_with_config()会返回NULL。

int  event_config_set_num_cpus_hint(struct event_config *cfg, int cpus)

该接口目前仅在Windows上使用IOCP时才支持,未来版本其他平台上也许也会支持。调用该接口,使得由event_config配置生成的event_base可以在多线程时更加有效的使用给定的cpu个数。注意,注意这仅仅是一个提示:event_base使用的CPU可能比你选择的要少。

intevent_config_set_max_dispatch_interval(struct event_config *cfg,

const struct timeval *max_interval, intmax_callbacks,

int min_priority);

该接口可以防止优先级反转。这是通过在检查更高优先级的events之前,限制有多少低优先级的event回调可以被调用而实现的。如果max_interval非NULL,在每次回调之后,event loop都会检查时间,而且经过max_interval时间之后,重新扫描更高优先级的events。如果max_callbacks非0,那么max_callback个回调被调用之后,event
loop会检查更多的events。这些规则针对min_priority以及以上的events有效。

的max_callbacks,那么在检查新的events之前,最多运行max_callbacks个回调。

该接口可以减少高优先级events的延迟。而且在有多个低优先级events时,避免出现优先级倒置。但是这是以降低吞吐量为代价的。

         max_interval :经过该时间之后,Libevent应该停止运行回调,而检查新的events,如果该参数为NULL,则无此时间限制。

max_callbacks:经过max_callbacks个回调之后,Libevent应该停止运行回调,并且检查更多的events。如果该参数为-1,则无此个数限制。

min_priority:低于该优先级的events,max_interval和max_callbacks将不会生效。如果该值为0,则所有优先级的events都会生效。如果置为1,则针对优先级为1,以及更高优先级的events才会生效。

struct event_config *cfg;

struct event_base *base;

int i;

/* My program wants to use edge-triggered events if atall possible.  So

   I'll try to geta base twice: Once insisting on edge-triggered IO, and

   once not. */

for (i=0; i<2; ++i) {

cfg =event_config_new();

    /* I don't likeselect. */

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 gethere, event_base_new_with_config() returned NULL.  If

       this is thefirst time around the loop, we'll try again without

       settingEV_FEATURE_ET.  If this is the secondtime around the

       loop, we'llgive 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 twopriorities.  I expect that

   some of mypriority-1 events are going to have pretty slow callbacks,

   so I don't wantmore than 100 msec to elapse (or 5 callbacks) before

   checking forpriority-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);

以上所有的函数和类型都在<event2/event.h>中声明。

三:检测event_base的后端方法

有时你可能需要知道一个event_base实际具有哪些特性,或者使用哪一个后端方法。

const char **event_get_supported_methods(void);

event_get_supported_methods()返回一个指向数组的指针。该数组包含所有当前Libevent所支持的后端方法的名字,该数组最后一个元素为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]);

}

注意:该函数返回的,是Libevent编译时支持的一系列后端方法,有可能Libevent在尝试运行时,操作系统实际上并不支持所有的方法。比如,如果你使用OSX系统的话,那么kqueue可能会有太多的漏洞而无法使用。

const char *event_base_get_method(conststruct event_base *base);

enum event_method_featureevent_base_get_features(const struct event_base *base);

event_base_get_method()方法返回的是event_base实际使用的后端方法名称。event_base_get_features()返回它所支持的特性的掩码组合。

struct event_base *base;

enum event_method_feature f;

base = event_base_new();

if (!base) {

puts("Couldn't get anevent_base!");

} else {

printf("Using Libevent with backendmethod %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("");

}

这些方法定义在文件<event2/event.h>中。

四:释放event_base

当一个event_base完成任务的时候,就可以调用event_base_free释放它。

void event_base_free(structevent_base *base);

注意,该函数并不释放任何与event_base所关联的events,也不会关闭sockets,更不会释放他们的指针。该方法在<event2/event.h>中定义。

五:设置event_base 的优先级

Libevent支持在event上设置多个优先级。默认情况下,一个event_base仅有一个优先级。可以通过函数event_base_priority_init来设置event_base的优先级等级数。

int  event_base_priority_init(struct event_base*base, int n_priorities);

该函数成功时返回0,失败是返回-1。参数base是需要修改的event_base, n_priorities是支持的优先级等级数。该参数至少为1. 调用该函数之后,(最高)到n_priorities -1(最低)。

常数EVENT_MAX_PRIORITIE,是n_priorities的值的上限。如果使用比该常数还要大的数调用该函数,就会发生错误。

注意,必须在任何events变为激活时调用该函数。最好是创建event_base之后就立即调用它。

调用event_base_getnpriorities(),可以得到当前event_base所支持的优先级等级个数。

int event_base_get_npriorities(structevent_base *base);

该方法返回在event_base上配置的优先级等级数。所以如果该函数返回3,那么支持的优先级就是0,1和2.

默认情况下,所有关联到event_base的events的初始优先级都是n_priorities/ 2。

函数event_base_priority_init,在<event2/event.h>中定义。

六:fork之后,重新初始化event_base

并不是所有event后端,在fork之后都能正确工作。所以,如果你的程序使用fork(或其他系统调用)开始一个新进程,如果在fork之后,还想继续使用event_base,那么需要对其进行重新初始化。

int event_reinit(structevent_base *base);

该方法在成功是返回0,失败是返回-1.

struct event_base *base =event_base_new();

/* ... add some events to theevent_base ... */

if (fork()) {

/* In parent */

continue_running_parent(base); /*...*/

} else {

/* In child */

event_reinit(base);

continue_running_child(base); /*...*/

}

该方法在<event2/event.h>中定义。

七:过时的event_base方法

老版本的Libevent严重依赖于“当前”event_base的概念。“当前”event_base是指所有线程都共享的全局设置。如果你忘了指定需要哪一个event_base,那会得到“当前”的那一个。因为event_base不是线程安全的,所以这样很容易出错。

event_base_new的老版本是:

struct event_base*event_init(void);

该方法类似于event_base_new,将当前event_base设置为分配的event_base。没有任何其他方法可以改变当前base。

本文描述的函数有一些用于操作当前event_base的变体,这些函数与新版本函数的行为类似,只是它们没有event_base参数。

Current function

Obsolete current-base version

event_base_priority_init()

event_priority_init()

event_base_get_method()

event_get_method()

http://www.wangafu.net/~nickm/libevent-book/Ref2_eventbase.html

Libevent:3创建event_base的更多相关文章

  1. 【传智播客】Libevent学习笔记(二):创建event_base

    目录 00. 目录 01. 简介 02. 创建默认的event_base 03. 创建复杂的event_base 3.1 event_config_new函数 3.2 event_base_new_w ...

  2. R2:获取一个event_base

    原文链接:http://www.wangafu.net/~nickm/libevent-book/Ref2_eventbase.html 创建一个event_base 在你使用任何有意思的Libeve ...

  3. (转)Libevent(2)— event、event_base

    转自:http://name5566.com/4198.html 参考文献列表:http://www.wangafu.net/~nickm/libevent-book/ 此文编写的时候,使用到的 Li ...

  4. libevent之event_base

    event_base是libevent的事务处理框架,负责事件注册.删除等,属于Reactor模式中的Reactor. event_base结构体 event_base结构体定义于<event_ ...

  5. Libevent 的多线程操作

    起因是event_base 跨线程add/remove event 导致崩溃或者死循环. 据查:libvent 1.4.x是非线程安全的,要跨线程执行event_add,会有问题.因此传统做法是通过p ...

  6. libevent (二) 接收TCP连接

    libevent 接收TCP连接 Evconnlistener 机制为您提供了侦听和接受传入的 TCP 连接的方法.下面的函数全部包含在`<event2/listener.h>`中. ev ...

  7. 使用 libevent 和 libev 提高网络应用性能——I/O模型演进变化史

    构建现代的服务器应用程序需要以某种方法同时接收数百.数千甚至数万个事件,无论它们是内部请求还是网络连接,都要有效地处理它们的操作. 有许多解决方案,但事件驱动也被广泛应用到网络编程中.并大规模部署在高 ...

  8. Libevent详细说明

    文章来自官方文档的部分翻译:http://www.wangafu.net/~nickm/libevent-book/ 通过这部分的了解,基本上可以使用libevent的常用功能了.有时间建议直接看官方 ...

  9. libevent系列文章

    Libevent 2 提供了 bufferevent 接口,简化了编程的难度,bufferevent 实际上是对底层事件核心的封装,因此学习 bufferevent 的实现是研究 Libevent 底 ...

随机推荐

  1. Java中移动文件或目录的方法盘点

    本文不再更新,可能存在内容过时的情况,实时更新请移步原文地址:Java中移动文件或目录的方法盘点: import org.apache.commons.io.FileUtils; import jav ...

  2. ASP.NET Core修改IOC为Autofac

    如下是我为了了解如何更换ASP.NET Core中的IOC而查找的文章,如果大家英文OK的,可以直接前往阅读,同时也已经有简单的github例子供大家参考. 参考文章: ASP.NET Core文档: ...

  3. 20190811-Recover

    好点了. 恍惚中,是她么? 考试前,我感觉很差. 考试频繁于我改题速度. 考试过程: 首先通看三题,太棒了,没有tenggang了 T1,前缀和(我终于提升了??) T2,明显不会,但是我想用贪心, ...

  4. spring boot指定外部配置的坑

    外部配置文件所在目录path/to/dir 指定--spring.config.location=path/to/dir 项目启动,没有使用任何配置文件,项目外和jar包中的都没有使用 这是因为其把p ...

  5. Linux 下用Win共享

    让win能访问到 linux 的smb 共享: linux 安装 samba: apt-get install samba #然后 vim /etc/samba/smb.conf #找到securit ...

  6. 关于JavaScript的一些不得不知道的事儿

    1.JavaScript不区分整数和浮点数,统一用Number表示. 2.NaN这个特殊的Number与所有其他值都不相等,包括它自己: NaN===NaN; //false 唯一能判断NaN的方法是 ...

  7. jnhs-netbeans maven Failed to execute goal org.apache.maven.plugins:maven-clean-plugin:2.4.1:clean (default-clean) on project

    w 无法完成清理 出现这种错误,通常是由于启动了另一个tomcat 进程或者运行的javaw.exe进程,导致报错. 直接运行工程启动后再清理就好了 或者 重启大法

  8. html中有序列表标签ol,li的高级应用

    本文主要介绍html中有序列表标签ol,li的高级应用, 在网页设计时我们设计有序列表内容时,经常会在每个ITEM前手工加上一个数值,或是由程序加上这个数值. 而如果使用有序列表标签ol和li,则不需 ...

  9. 开始使用Apache弗林克和Mapr Streams

    Introduction MapR Ecosystem Package 2.0 (MEP) is coming with some new features related to MapR Strea ...

  10. 百分比宽度并排元素浮动之后,设置margin,padding换行的问题

    今天遇到一个问题, 如下图,右边的div加了内边距换行: 解决方法: box-sizing: border-box;