R2:获取一个event_base
原文链接:http://www.wangafu.net/~nickm/libevent-book/Ref2_eventbase.html
创建一个event_base
在你使用任何有意思的Libevent函数之前,你需要分配一个或多个event_base结构.每一个event_base结构含有一组events,并且可以告知你哪一些events是就绪的.
如果一个event_base是以加锁模式创建的,那么在多个线程访问它是安全的.然而,事件循环却只能跑在一个线程内.所以说,如果你想要对IO事件有多线程的轮询,你需要为每一个线程都分配一个event_base。
Tip:未来版本的Libevent可能会支持多线程的IO事件轮询.
每一个event_base都有一个"方法"或者说后台,event_base根据这个来判断哪一个event已经就绪.目前确认的方法有:
select
poll
epoll
kqueue
devpoll
evport
win32
用户可以通过设置环境变量的方式禁用特定的后台方法.比如你不想使用kqueue,那么设置一个叫EVENT_NOKQUEUE的环境变量.如果你想禁用程序内部的后台方法,看下面对event_config_avoid_method()的说明.
创建一个默认的event_base
event_base_new()函数分配并返回一个新的默认配置的event_base。该函数检测环境变量并返回一个指向新的event_base的指针.如果出错的话则返回NULL.
当在众多方法(指上文中提到的事件多路分离的方法:select,poll,epoll等)中选择时,它会选择当前操作系统支持的最快的方法.
Interface
struct event_base *event_base_new(void);
对大多数程序来讲,这就是你所需全部了.
event_base_new()函数在<event2/event.h>中声明.它是在Libevent 1.4.3中第一次引入的.
创建一个复杂的event_base
如果你想对获取一个什么样的event_base有更多的控制权,你需要用到event_config.一个event_config是一个不透明的结构(opaque structure),其中含有你对event_base的预设信息.当你想获取一个event_base,你向event_base_new_with_config()即可.
Interface
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);
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_falg()告知Libevent在创建event_base时设置一个或多个下述的运行时标志.
已知的用来传给event_config_require_feature()的特征值有:
EV_FEATURE_ET
EV_FEATURE_O1
要求一个增加事件,删除事件,激活事件的复杂度为O(1)的后台方法.
EV_FEATURE_FDS
要求一个支持任意文件描述符类型,而不仅仅是sockets的后台方法.
已知的用来传给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的分派逻辑,而不是在需要时才启用.(On Windows only, this flag makes Libevent enable any necessary IOCP dispatch logic on startup, rather than on-demand.)
- EVENT_BASE_FLAG_NO_CACHE_TIME
-
在每一次超时调用后检测当前时间,而不是在事件循环就绪可以运行超时回调函数时检测当前时间。注意:这可能导致程序消耗更多的CPU。
- EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST
-
这个标志告知Libevent如果要用epoll的话,用基于"changelist"的后台方法会更快,也是安全的.如果在多次后台调度函数调用之间同一个文件描述符的状态发生了多次改变,使用epoll-changelist后台方法可以避免不必要的系统调用,当你向Libevent传递任何一个由dup()或是类似函数复制的文件描述符时,这样(指使用epoll-changelist)会触发一个导致很多错误结果的内核bug。
- EVENT_BASE_FLAG_PRECISE_TIMER
-
默认地,Libevent尝试使用当前操作系统所能提供的最快的计时机制.如果操作系统有一种慢一些的但是精度更高的计时机制的话,设置这个标志将告知Libevent使用这种更慢但精度更高的机制,如果没有,这个标志将不起作用.
上述所有对event_config操作的函数都有两个返回值:0代表成功,-1代表失败.
Note
|
很容易创建这样一个event_config:它要求你的操作系统并未提供的后台方法.以Libevent 2.0.1-alpha为例,在Windows下没有O(1)的后台方法,在Linux下没有同时满足 EV_FEATURE_FDS and EV_FEATURE_O1的后台方法.如果你要求一个Libevent无法满足的配置,event_base_new_with_config()会返回空. |
Interface
int event_config_set_num_cpus_hint(struct event_config *cfg, int cpus)
这个函数目前只在windows平台下使用IOCP时有用,尽管未来在别的平台可能也会有用.调用这个函数告诉event_base在多线程处理时要充分利用给定数量的cpu.注意这只是一个(该函数对event_base的)暗示:event base可能使用更多或更少的CPU.
int event_config_set_max_dispatch_interval(struct event_config *cfg,
const struct timeval *max_interval, int max_callbacks,
int min_priority);
struct event_config *cfg;
struct event_base *base;
int i; /* My program wants to use edge-triggered events if at all possible. So
I'll try to get a base twice: Once insisting on edge-triggered IO, and
once not. */
for (i=; i<; ++i) {
cfg = event_config_new(); /* I don't like select. */
event_config_avoid_method(cfg, "select"); if (i == )
event_config_require_features(cfg, EV_FEATURE_ET); base = event_base_new_with_config(cfg);
event_config_free(cfg);
if (base)
break; /* If we get here, event_base_new_with_config() returned NULL. If
this is the first time around the loop, we'll try again without
setting EV_FEATURE_ET. If this is the second time around the
loop, we'll give up. */
}
Example: Avoiding priority-inversion
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 = { , * };
event_config_set_max_dispatch_interval(cfg, &msec_100, , ); base = event_base_new_with_config(cfg);
if (!base)
/* Handle error */; event_base_priority_init(base, );
这些函数和类型在<event2/event.h>中声明.
EVENT_BASE_FLAG_IGNORE_ENV标志始于Libevent 2.0.2-alpha.EVENT_BASE_FLAG_PRECISE_TIMER标志始于Libevent 2.1.2-alpha.event_config_set_num_cpus_hint()始于Libevent 2.0.7-rc,event_config_set_max_dispatch_interval()始于Libevent 2.1.1-alpha.这一部分提到的其它函数或类型始于Libevent 2.0.1-alpha.
检测event_base的后台方法
有时你可能想知道一个event_base究竟含有哪些特征或者使用了哪种后台方法.
Interface
const char **event_get_supported_methods(void);
event_get_supported_methods()函数返回一个指向数组的指针,数组内存放的是当前版本Libevent支持的方法.数据内的最后一个元素为空.
Example
int i;
const char **methods = event_get_supported_methods();
printf("Starting Libevent %s. Available methods are:\n",
event_get_version());
for (i=; methods[i] != NULL; ++i) {
printf(" %s\n", methods[i]);
}
Note
|
这个函数返回一个方法列表,Libevent是被编译成支持这些方法的.然而,你的操作系统可能实际上并不支持这些方法.比如,在某些OSX版本下kqueue使用起来是很多BUG的 |
Interface
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()返回一个它所支持的特性的位掩码.
Example
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("");
}
这些函数定义于<event2/event.h>.event_base_get_method()第一次出现于Libevent 1.4.3.其余的始于Libevent 2.0.1-alpha.
释放event_base
当你不再需要event_base,你可以用event_base_free()释放它.
Interface
void event_base_free(struct event_base *base);
注意这个函数不会释放掉任何正与event_base关联的事件,或是关闭与这些事件相关的sockets,或是释放它们的指针所指空间.
event_base_free()函数定义在<event2/event.h>中.始于Libevent 1.2.
设置优先级
Libevent支持对一个event设置多个优先级.默认地,一个event_base只支持一个优先级.你可以通过调用event_base_priority_init()为一个event_base设置优先级的数量.
Interface
int event_base_priority_init(struct event_base *base, int n_priorities);
该函数成功返回0,失败返回-1.参数base是待修改的event_base,n_priorties是支持的优先级的数量.n_priorities至少要是1.优先级从0(最重要)到n_priorities-1(最不重要).
有一个常量,EVENT_MAX_PRIORITIES,标识了n_priorities的最大值.调用上述函数时,传一个超过EVENT_MAX_PRIORITIES的n_priorities参数是错误的行为.
int event_base_get_npriorities(struct event_base *base);
该函数的返回值为当前base中配置的优先级数量.所以如果event_base_get_npriorities()返回3,那么可选的优先级的值为0,1,2.
Example
For an example, see the documentation for event_priority_set below.
默认地,所有和base相关的事件会被初始化为优先级为n_priorities/2.
event_base_priority_init()定义于<event2/event.h>.它始于Libevent 1.0.event_base_get_npriorities()始于Libevent 2.1.1-alpha
在fork()之后重新初始化event_base
不是所有的事件后台在fork()之后还可以保持干净.(Not all event backends persist cleanly after a call to fork()).所以,如果你的程序使用了fork()或相关的系统调用来开启一个新的进程,而你想继续使用之前的event_base,你需要重新初始化它.
Interface
int event_reinit(struct event_base *base);
该函数成功返回0,失败返回-1.
Example
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); /*...*/
}
event_reinit()定义于<event2/event.h>.始于Libevent 1.4.3-alpha.
废弃的event_base函数
旧版的Libevent严重依赖于“当前”event_base这个概念.所谓的“当前”event_base,是一个被所有线程共享的全局设置.如果你忘了指定你想使用哪一个event_base,那么你得到的就是"当前"的.而由于event_base不是线程安全的,这种行为非常容易导致错误.
相较于如今版本的event_base_new(),过去有:
Interface
struct event_base *event_init(void);
这个函数类似于event_base_new(),它将分配的base设置为当前base.除此之外,没有别的改变当前base的方式了.
这部分提到的作用于当前base的函数有许多变体.这些(旧版本中的)函数和现在的函数功能类似,除了它们不接受base参数.
当前版本 | 已弃用的版本 |
---|---|
event_base_priority_init() |
event_priority_init() |
event_base_get_method() |
event_get_method() |
R2:获取一个event_base的更多相关文章
- Entity Framework 6 Recipes 2nd Edition(12-8)译 -> 重新获取一个属性的原始值
12-8. 重新获取一个属性的原始值 问题 在实体保存到数据库之前,你想重新获取属性的原始值 解决方案 假设你有一个模型 (见 Figure 12-11) 表示一个员工( Employee),包含工资 ...
- Entity Framework 6 Recipes 2nd Edition(13-2)译 -> 用实体键获取一个单独的实体
问题 不管你用DBFirst,ModelFirst或是CodeFirst的方式,你想用实体键获取一个单独的实体.在本例中,我们用CodeFirst的方式. 解决方案 假设你有一个模型表示一个Paint ...
- python 获取一个列表有多少连续列表
python 获取一个列表有多少连续列表 例如 有列表 [1,2,3] 那么连续列表就是 [1,2],[2,3],[1,2,3] 程序实现如下: 运行结果:
- openstack数据库获取一个虚机的floating_ip, fix_ip, project_name, user_name, hostname, host
转载请注明 http://www.cnblogs.com/juandx/p/5418204.html openstack有3个库,nova,neutron,keystone,我现在需要做的是跨库联表 ...
- PHP如何随机获取一个二维数组中的一个值
获取一个数组: $awardid_list=pdo_fetchall('select id from '.tablename($this->table_award)); 这是微擎的写法哈,意思就 ...
- sql 根据指定条件获取一个字段批量获取数据插入另外一张表字段中+MD5加密
/****** Object: StoredProcedure [dbo].[getSplitValue] Script Date: 03/13/2014 13:58:12 ******/ SET A ...
- C# 设置和获取一个字节的某一位的值的方法
自己工作中遇到需要对单字节的高位.低位进行赋值,即一个字节byte,想要给每一位都赋值,这个值是动态来的,是0或是1. 好不容易收集到一些珍贵资料,整理一下: 一.设置 方法code: /// < ...
- 获取一个字符串Hello world中world首次出现的位置
获取一个字符串Hello world中world首次出现的位置 var str=“Hello world!” document.write(str.indexOf("world") ...
- java中的反射机制,以及如何通过反射获取一个类的构造方法 ,成员变量,方法,详细。。
首先先说一下类的加载,流程.只有明确了类这个对象的存在才可以更好的理解反射的原因,以及反射的机制. 一. 类的加载 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三 ...
随机推荐
- mongodb教程
http://sheperd.blog.163.com/blog/static/19525511920119111149046/ http://www.cnblogs.com/oec2003/arch ...
- 值得收藏的Javascript代码
1 Javascript数组转换为CSV格式 首先考虑如下的应用场景,有一个Javscript的字符型(或者数值型)数组,现在需要转换为以逗号分割的CSV格式文件.则我们可以使用如下的小技巧,代码如 ...
- CPU使用率计算
昨天接到临时任务,需要将一个工作线程执行真正工作的时机推迟到CPU空闲时执行.当时第一感觉认为是将线程优先级设置为空闲级别就行了,以为只有CPU空闲下来才会去跑这个线程,实际上应该不是,毕竟即时是空闲 ...
- adb devices: no permissions
现象: #sudo adb root Error:insufficient permissions for device #adb devices List of devices attached ? ...
- Hbase 设计与开发实战
Hbase 概述 大数据及 NoSQL 的前世今生 传统的关系型数据库处理方式是基于全面的 ACID 保证,遵循 SQL92 的标准表设计模式(范式)和数据类型,基于 SQL 语言的 DML 数据交互 ...
- Linux下Django的安装
1.下载Django.地址:https://www.djangoproject.com/download/ 2.解压3中得到的Django-1.6.2.tar.gz.使用下面的命令进行解压,解压后在当 ...
- 在SQL中使用自定义函数
由于数据库的一个表字段中多包含html标签,现在需要修改数据库的字段把html标签都替换掉.当然我可以通过写一个程序去修改,那毕竟有点麻烦.直接在查询分析器中执行,但是MS SQL Server并 ...
- Android ImageView
如上图,drawable中不只是可以放bitmap 还可以定制不同形状 <?xml version="1.0" encoding="utf-8"? ...
- Java内部类实现伪方法级多线程
最近碰到一个问题,就是用户在填写相关信息提交后,后台需要将一些文件同步到另外一台服务器,而这个时候,由于用的是spring的框架,导致前端页面需要等待文件同步完成,才能弹出提示信息.相信大家在很多时候 ...
- C++中struct和class的区别 [转]
一. C++中的struct对C中的struct进行了扩充,它已经不再只是一个包含不同数据类型的数据结构了,它已经获取了太多的功能. struct能包含成员函数吗? 能! struct能继承吗? ...