zoukankan      html  css  js  c++  java
  • libevent简介[翻译]5 获得一个event_base

    http://www.wangafu.net/~nickm/libevent-book/Ref2_eventbase.html

    创建一个event_base

    在使用任何libevent函数之前,需要先创建一个或是多个event_base。每一个event_base都包含一个事件集合,它可以准确的通知哪一个事件到达了。

    如果event_base使用了锁,那么在多线程下调用就是安全的。它的事件循环只能在一个线程中使用,如果想在多个线程中遍历IO,就需要为每一个线程创建一个event_base

    将来可能会提供在多个线程下使用的event_bases

    每个event_base都有一个解决方案,后端决定使用哪一个,现有的方案有:

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

    可以通过环境变量禁用其中的功能,如果想关闭kqueue,可以设置EVENT_NOKQUEUE环境变量。如果想从程序中禁用某个方案,可以调用event_config_avoid_method()

    设置默认event_base

    event_base_new()申请并返回一个新的event base。如果出错返回NULL

    接口

    struct event_base *event_base_new(void);

    设置一个复杂的event_base

    如果想自定义一些属性,需要调用event_configevent_config是一个不透明的结构体,保存着event_base的首选项信息。使用event_base_new_with_config()创建event_base,创建的时候可以把event_config传递进去。

    接口

    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,创建完成后可以把这个配置结构体删除了。

    接口

    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()可以禁用一些功能。event_config_require_feature()设置我们使用的功能。event_config_set_flag()设置多个运行时的标识

    event_config_require_features()可以使用的参数有:

    EV_FEATURE_ET

    • 使用边界触发

    EV_FEATURE_O1

    • 添加、删除或是激活一个event是O(1)的操作

    EV_FEATURE_FDS

    • 可以使用任意的文件描述符,而不仅仅是socket

    对于event_config_set_flag()可以使用的参数有:

    EVENT_BASE_FLAG_NOLOCK

    • 对于event_base的操作,不实用锁,这样可以节省一点点时间,但是在多线程下工作会有问题

    EVENT_BASE_FLAG_IGNORE_ENV

    • 禁止使用EVENT_*所有的环境变量。谨慎使用这个标识,如果出现问题,很难调试。

    EVENT_BASE_FLAG_STARTUP_IOCP

    • 启动时就使用IOCP,这个仅仅在Windows下有效。

    EVENT_BASE_FLAG_NO_CACHE_TIME

    • 把默认的在每次事件循环超时的时候检查当前时间,替换成不是整个循环,而是每个超时回调之后都检查当前时间,这样会大大增加CPU的消耗,带来的是更精确的时钟。慎重考虑。

    EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST

    • 这个很明显是针对epoll的,就是如果使用epoll,那么就可以使用changelist。因为changelist可以在同一个fd多次被修改的情况下避免不必要的系统调用;同样,如果如果你传入了通过dup()克隆或是它自己的变体的fd给libevent,那么也会导致内核错误。如果不是epoll模型,这个标识是没有作用的。同样可以通过EVENT_EPOLL_USE_CHANGELIST环境变量打开changelist。

    EVENT_BASE_FLAG_PRECISE_TIMER

    • libevent在不同平台下都会使用该系统提供的更快的时钟机制,但是如果该系统上有稍微慢一点的但是更精确的时钟机制,可以通过这个参数设置使用。但是如果系统上没有这种慢一点但是更精确的时钟机制,这个标识不会有任何作用。

    上面的这些针对event_config的函数调用返回值都是:0-成功 -1-失败

    注意

    我们可以很容易的设置event_config,不管底层系统是否支持。比如在Libevent 2.0.1-alpha这个版本上,在Windows下没有O(1)的实现,在Linux下没有EV_FEATURE_FDSEV_FEATURE_O1,如果你设置了libevent无法实现的标识,event_base_new_with_config()就会返回NULL

    接口

    int event_config_set_num_cpus_hint(struct event_config *cfg, int cpus)
    

    这个函数目前只在Windows下有效,将来可能在其他平台上也可用。调用这个函数就是设置event_config使得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);
    

    在libevent中有事件优先级,这个函数的作用就是打破事件优先级,让libevent在高优先级的事件处理之前可以处理多少个低优先级的事件,因为如果高优先级的事件一直很多,处理不完,就会导致低优先级的事件永远无法处理。如果max_interval传入的不是NULL,事件循环会在每次回调后检查时钟,当max_interval超时后就重新搜索高优先级的事件。如果max_callbacks是非负的,事件循环还会在调用完所有max_callbacks回调后再调用更多其他事件。这个规则适用于任何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=0; i<2; ++i) {
        //创建一个cfg
        cfg = event_config_new();
    
        /* I don't like select. */
        //屏蔽使用select方法
        event_config_avoid_method(cfg, "select");
    
        if (i == 0)
            //使用ET边界触发
            event_config_require_features(cfg, EV_FEATURE_ET);
    
        //用上面的cfg创建一个event base
        base = event_base_new_with_config(cfg);
    
        //释放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 */;
    
    /* 这里有两个优先级的event在跑。由于优先级1(也就是优先级高)的事件运行的慢,
       所以希望优先级0(也就是优先级低)更多的调用一些。
       这里设置的就是最多100毫秒或是回调5次之后,肯定调用一次优先级0的事件 */
    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);
    

    检测event_base底层有效的模型

    有时候我们想知道event_base底层有哪些模型可用

    接口

    const char **event_get_supported_methods(void);
    

    这个函数会返回一个数组,里面列出了可用的模型。最后一个指向NULL表示结束。

    示例

    int i;
    const char **methods = event_get_supported_methods();
    printf("Starting Libevent %s.  Available methods are:
    ",
        event_get_version());
    for (i=0; methods[i] != NULL; ++i) {
        printf("    %s
    ", methods[i]);
    }
    

    接口

    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_get_features获取将来可能支持的模型

    示例

    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

    当我们使用完后需要释放event_base的资源

    void event_base_free(struct event_base *base);
    

    需要注意,这里仅仅是释放event_base,并不会释放任何与它关联的变量,比如socket,或是一些指针。

    event_base设置优先级

    libevent支持为event设置多个优先级,但是event_base只能设置一个

    int event_base_priority_init(struct event_base *base, int n_priorities);
    

    成功返回0,失败返回-1。event_base的n_priorities必须是1,而新创建的event可以是0,也可以是-1

    EVENT_MAX_PRIORITIES定义了最高优先级,如果设置过高,会报错

    在调用任何event之前设置它的优先级,最好是在创建完成后就设置好。

    可以调用int event_base_get_npriorities(struct event_base *base);获取当前event的优先级。如果返回值是3,就表示0,1,2三个优先级是可用的。

    一般情况下,新创建的event的优先级都设置为与它关联的event_base的二分之一,n_priorities / 2

    fork()之后重新初始化event_base

    fork()之后event_base的有些信息并没有完全清理,所以需要初始化

    int event_reinit(struct event_base *base);
    

    示例

    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_base函数

    以前版本的libevent很大程度上,在实现是想上,与当前的event_base一样。当前的event_base是一个全局共享的资源。如果没有特殊定义,你是用的是当前的event_base,记住,event_base是线程不安全的,不要使用的时候出错。

    建议使用struct event_base *event_init(void);来代替event_base_new()

    Current function Obsolete current-base version
    event_base_priority_init() event_priority_init()
    ---- ----
    event_base_get_method() event_get_method()
  • 相关阅读:
    Go的几种函数式编程范例
    换零钱和快速幂
    随笔不是博客
    leetcode-51
    leetcode-50
    拨号器
    简易计算器的实现
    python入门:1-100所有数的和
    python入门:输出1-10以内除去7的所有数(简)
    python入门:输出1-10以内除去7的所有数(自写)
  • 原文地址:https://www.cnblogs.com/studywithallofyou/p/13086902.html
Copyright © 2011-2022 走看看