Libevent:3创建event_base
在使用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的更多相关文章
- 【传智播客】Libevent学习笔记(二):创建event_base
目录 00. 目录 01. 简介 02. 创建默认的event_base 03. 创建复杂的event_base 3.1 event_config_new函数 3.2 event_base_new_w ...
- R2:获取一个event_base
原文链接:http://www.wangafu.net/~nickm/libevent-book/Ref2_eventbase.html 创建一个event_base 在你使用任何有意思的Libeve ...
- (转)Libevent(2)— event、event_base
转自:http://name5566.com/4198.html 参考文献列表:http://www.wangafu.net/~nickm/libevent-book/ 此文编写的时候,使用到的 Li ...
- libevent之event_base
event_base是libevent的事务处理框架,负责事件注册.删除等,属于Reactor模式中的Reactor. event_base结构体 event_base结构体定义于<event_ ...
- Libevent 的多线程操作
起因是event_base 跨线程add/remove event 导致崩溃或者死循环. 据查:libvent 1.4.x是非线程安全的,要跨线程执行event_add,会有问题.因此传统做法是通过p ...
- libevent (二) 接收TCP连接
libevent 接收TCP连接 Evconnlistener 机制为您提供了侦听和接受传入的 TCP 连接的方法.下面的函数全部包含在`<event2/listener.h>`中. ev ...
- 使用 libevent 和 libev 提高网络应用性能——I/O模型演进变化史
构建现代的服务器应用程序需要以某种方法同时接收数百.数千甚至数万个事件,无论它们是内部请求还是网络连接,都要有效地处理它们的操作. 有许多解决方案,但事件驱动也被广泛应用到网络编程中.并大规模部署在高 ...
- Libevent详细说明
文章来自官方文档的部分翻译:http://www.wangafu.net/~nickm/libevent-book/ 通过这部分的了解,基本上可以使用libevent的常用功能了.有时间建议直接看官方 ...
- libevent系列文章
Libevent 2 提供了 bufferevent 接口,简化了编程的难度,bufferevent 实际上是对底层事件核心的封装,因此学习 bufferevent 的实现是研究 Libevent 底 ...
随机推荐
- [NOI OJ]6044:鸣人和佐助
6044:鸣人和佐助 查看 提交 统计 提问 总时间限制: 1000ms 内存限制: 65536kB 描述 佐助被大蛇丸诱骗走了,鸣人在多少时间内能追上他呢? 已知一张地图(以二维矩阵的形式表示) ...
- Go之路之go语言结构
Go Hello World 实例 package main //定义了包名,必须在源文件中非注释的第一行指名这个文件属于哪个包,每个Go应用程序都包含一个名为main的包 import " ...
- NOIP2017解题报告
啊不小心点发布了,懒得删了就这样吧,虽然还没写完,也不打算写了大概. d1t1 结论题 没什么好说的 d1t2 模拟 没什么好说的 d1t3 70分算法其实比较好想. 没有0边,就跑最短路,然后按di ...
- GIL(全局解释器锁) 理解
GIL 锁,全局解释器锁,作用就是,限制多线程同时执行,保证同一时间内只有一个线程在执行. 线程非独立的,所以同一进程里线程是数据共享,当各个线程访问数据资源时会出现竞状态,即数据可能会同时被多个 ...
- TZ_05_Spring_Transaction的纯注解开发
1.数据库配置 jdbcConfiguation.java 1>使用Spring的EL表达式配合@Value()注解 @Value("${jdbc.Driver}") pri ...
- Jquery 判断值是否存在于数组之内
var strArray=str.split(","); var fixed_init=function(v){ if($.inArray(v,strArray)==-1){ // ...
- 【linux配置】Linux同步网络时间
Linux同步网络时间 1.date '+%Y%M%D' 按照格式显示当前日期,结果如下: [root@LAMP ~]# date "+%Y-%m-%d %H:%M:%S" -- ...
- wpf样式与行为
- C++使用stringstream分割字符串
在这里查看getline的函数声明如下: 可以看到,第三个参数delim是分隔符,可以指定不同的分隔符,如果不指定的话就默认是'\n'. 举个例子:
- VC开发多语言界面 多种方法(非常easy) 有源代码
源代码地址(专业定制程序:MCU,Windows,Android .VC串口,Android蓝牙等不限.) (需源代码先留邮箱)先上图 1.通过遍历 得到全部控件ID号与TEXT,得到一个中文语言配置 ...