在使用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

最新文章

  1. 用java开发微信公众号:接收和被动回复普通消息(三)
  2. js中array的filter用法
  3. iOS UITableview
  4. poj3263 Tallest Cow
  5. 【LeetCode OJ】Palindrome Partitioning II
  6. C++类型转化
  7. 关于HTML5标签不兼容(IE6~8)
  8. javascript调用外部wpf的方法
  9. STL_iterator迭代器(2)——几种迭代器对象的用法
  10. Apache 开启 Https
  11. C中的正则函数sscanf
  12. Delphi流的操作
  13. 记一下flex弹性布局
  14. Oracle EBS R12经验谈(二)
  15. 自定义chromium浏览器
  16. MySQL表最大能达到多少?
  17. 『TensorFlow』分类问题与两种交叉熵
  18. js 设置img标签的src资源无法找到的替代图片(通过img的属性设置)
  19. git笔记:通过给grunt-inline打tag看tag操作
  20. &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=7&quot; /&gt;意思是将IE8用IE7进行渲染,使网页在IE8下正常

热门文章

  1. Sql Server实现自动增长
  2. 【python之路35】FTP文件断电续传作业
  3. HDU2056
  4. idea目录结构子目录在父目录后面跟着改成树形结构
  5. 关于python的字典操作
  6. Python之路,Day5 - 常用模块学习 (转载Alex)
  7. day 52
  8. P3303 [SDOI2013]淘金
  9. 2018 8.8 提高A组模拟赛
  10. Codeforces 455C