event_base

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的demo
threads[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
}

你可能感兴趣的:(Libevent)