博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
event_base
阅读量:4035 次
发布时间:2019-05-24

本文共 6280 字,大约阅读时间需要 20 分钟。

event_base 介绍

  一个event_base就是一个Reactor框架。我们在调用任何Libevent的函数前,我们都是需要先申请 event_base 结构体。对于一个event_base结构来说,它会保存一系列的event事件并且以轮训的方式去关注每一个事件,去查看哪一个事件是就绪的。(事件就绪可以从unp第6章 I/O模型中有讲到)

  如果一个 event_base设置了使用lock,那么它在多线程之间访问就是安全的。虽然event_base 可以在多线程中使用,但是一个loop仅仅只能在一个线程内。如果我们想多个线程都去轮训,那么我们只能每一个线程去申请一个event_base。
  Libevent是基于Reactor模式的一个网络库,也是基于多路复用的一个网络库。所以每一个event_base都有一个对应的多路复用的method,event_base支持的所有method如下:

  • select
  • poll
  • epoll
  • kqueue
  • devpoll
  • evport
  • win32

我们可以取消(disable)指定的method通过环境变量,比如设置 EVENT_NOQUEUE 环境变量。也可以通过调用event_config_avoid_method函数来关闭相应的method。(下面有这个函数介绍)

event_base 构造

默认的event_base
struct event_base *  event_base_new (void)

  当我们调用event_base_new函数的时候,这个函数会检测环境变量然后去申请一个相应配置的event_base返回回来。在构造的时候它选择的method是当前OS支持最快的method。大多数场景,我们都是直接调用这个函数来申请event_base的。

current_base
struct event_base *event_init(void)下面是Libevent对event_init 的源码实现struct event_base *event_init(void)  {    struct event_base *base = event_base_new();     if (base != NULL)         current_base = base;       return (base); }申请多个 event_base的demothreads[THREADMAX];for( int i = 0 ; i < THREADMAX; ++i){        threads[i].base_ = event_init();}

  Libevent有一个全局的eventbase叫做current_base变量。每次调用event_init的时候,都会为这个全局变量申请一个新的event_base。有的时候我们可以通过这个方式去申请多个event_base如上面的代码列子。

  对于current_base变量,Libevent有一系列的操作函数,它们默认的目标都是current_base。

Current function Obsolete current-base version
event_base_priority_init() event_priority_init()
event_base_get_method() event_get_method()
个性化event_base
event_config

  它是一个黑盒(不透明)的数据结构,我们并不能直接操作它的成员,我们只能靠相应的函数来操作它

struct event_config * event_config_new(void)

  它返回一个event_config 结构体

void event_config_free(struct event_config *cfg)

  使用完 config后,我们要释放所以调用这个函数

int event_config_avoid_method (struct event_config * cfg, const char * method)

这个函数就是我们上面提到的去关闭或者禁止某个method的函数

int event_config_require_features (struct event_config * cfg , enum event_method_feature feature)
enum event_method_feature {    EV_FEATURE_ET = 0x01,//需要一个支持ET模式的method    EV_FEATURE_O1 = 0x02,//需要一个支持 O(1)去操作每个event事件的method    EV_FEATURE_FDS = 0x04,//需要一个支持任意文件描述符的method(不只socket)};
int event_config_set_flag(struct event_config *cfg, enum event_base_config_flag flag)
enum event_base_config_flag {    EVENT_BASE_FLAG_NOLOCK = 0x01, //它可以提高访问event_base的速度,但是会    //导致线程安全问题    EVENT_BASE_FLAG_IGNORE_ENV = 0x02,//这个标志表示在选择method的时候忽略设    //置的环境变量,一般很少使用,它会增加debug难度 2.0.2版本    EVENT_BASE_FLAG_STARTUP_IOCP = 0x04,//仅在windows下开启IOCP    EVENT_BASE_FLAG_NO_CACHE_TIME = 0x08,//默认检测当前时间的时机是当eventloop    //在运行相应的回调函数前,它会去检测更新对应的callback函数的当前时间。开启这个    //选项后,不将是只更新将要运行的callback的当前时间。还要去更新剩下其他所有的活    //跃事件的的callback函数时间,这个选项会增加CPU利用率,谨慎使用    EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST = 0x10,//以 Changlist的方式使用epoll    //它可以减少系统调用,但是当fd是dup复制的时候这个选项可能会造成内核BUG!!!    EVENT_BASE_FLAG_PRECISE_TIMER = 0x20//让Libevent使用更精密的计时机制2.1.2};

以上三个操作 event_config的函数都是0成功,-1失败。

int event_config_set_num_cpus_hint(struct event_config *cfg, int cpus)

  这个函数只能在windows下当使用IOCP的时候调用,调用它可以设置使用多线程的时候,尽可能分配的核数, 2.0.7版本

int event_config_set_max_dispatch_interval(struct event_config *cfg,const struct timeval *max_interval, int max_callbacks,int min_priority);

  这个函数可以反正优先级逆制,第二个参数表示过多少时间周期去再一次检测高级的event,max_callback在检测前最多调用多少次这个低优先级的callback后去检测,第三个指对应的低优先级数, 2.1.1-alpha

构造个性化event_base

struct event_base *event_base_new_with_config(const struct event_config *cfg)

  很简单就是构造event_base

释放event_base
void event_base_free(struct event_base *base)

  释放event_base

event优先级

  默认event都是一个优先级,但是Libevent运行我们设计多优先级的event事件。优先级默认是从 0 ~ n_priorities-1 ,越小优先级越高

int event_base_priority_init(struct event_base *base, int n_priorities)

   必须在任意一个event成为活跃前就调用这个函数来设置优先级,最好在刚创建event_base后就初始化优先级,n_priorities 必须小于 EVENT_MAX_PRIORITIES。

  默认注册到event_base中的event优先级都是 n_priorities / 2.

int event_priority_set(struct event *ev, int pri)

  直接设置优先级

重启event_base在fork后

  并不是所有的method在fork之后,都能保持之前的event具有持久态,如果我们想fork之后使它之前的event的持久态仍然有效,需调重启函数

int event_reinit(struct event_base *base)

代码列子

设置ET
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=0; i<2; ++i) {    cfg = event_config_new();    /* I don't like select. */    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 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. */}
防止优先级反转设置
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 = { 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);
显示支持的所有method的列子

返回的一个字符串数组,最后一个是空指针

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]);}
显示当前event_base的method和event特性
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("");}
重启event_base
struct event_base *base = event_base_new();/* ... add some events to the event_base ... */if (fork()) {    /* In parent */    doSomething} else {    /* In child */    event_reinit(base);    doSomething}

转载地址:http://tmjdi.baihongyu.com/

你可能感兴趣的文章
java自定义容器排序的两种方法
查看>>
如何成为编程高手
查看>>
本科生的编程水平到底有多高
查看>>
AngularJS2中最基本的文件说明
查看>>
从头开始学习jsp(2)——jsp的基本语法
查看>>
使用与或运算完成两个整数的相加
查看>>
备忘:java中的递归
查看>>
DIV/CSS:一个贴在左上角的标签
查看>>
Solr及Spring-Data-Solr入门学习
查看>>
Vue组件
查看>>
python_time模块
查看>>
python_configparser(解析ini)
查看>>
selenium学习资料
查看>>
<转>文档视图指针互获
查看>>
从mysql中 导出/导入表及数据
查看>>
HQL语句大全(转)
查看>>
几个常用的Javascript字符串处理函数 spilt(),join(),substring()和indexof()
查看>>
javascript传参字符串 与引号的嵌套调用
查看>>
swiper插件的的使用
查看>>
layui插件的使用
查看>>