libevent学习——event_base

event_base

使用 libevent 函数之前需要分配一个或者多个 event_base 结构体。每个event_base 结构 体持有一个事件集合,可以检测以确定哪个事件是激活的。

如果设置 event_base 使用锁,则可以安全地在多个线程中访问它 。然而,其事件循环只能 运行在一个线程中。如果需要用多个线程检测 IO,则需要为每个线程使用一个 event_base

每个 event_base 都有一种用于检测哪种事件已经就绪的 “方法”,或者说后端。可以识别的方法有:

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

创建event_base

创建默认的event_base

event_base_new()函数分配并且返回一个新的具有默认设置的 event_base。函数会检测环境变量,返回一个到 event_base 的指针。如果发生错误,则返回 NULL。选择各种方法时,函数会选择 OS 支持的最快方法。

struct event_base *event_base_new(void);

大多数程序使用这个函数就够了。

创建复杂的event_base

要对取得什么类型的 event_base 有更多的控制,就需要使用 event_config
event_config 是一个容纳 event_base 配置信息的不透明结构体。需要 event_base时,将 event_config 传递给event_base_new_with_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,先调用 event_config_new()分配一个event_config。 然后,对 event_config 调用其它函数,设置所需要的 event_base 特征。最后,调用 event_base_new_with_config()获取新的 event_base。完成工作后,使用 event_config_free()释放 event_config

/**
   Enters an event method that should be avoided into the configuration.

   This can be used to avoid event mechanisms that do not support certain
   file descriptor types, or for debugging to avoid certain event
   mechanisms.  An application can make use of multiple event bases to
   accommodate incompatible file descriptor types.

   @param cfg the event configuration object
   @param method the name of the event method to avoid
   @return 0 on success, -1 on failure.
*/
EVENT2_EXPORT_SYMBOL
int event_config_avoid_method(struct event_config *cfg, const char *method);

/**
   A flag used to describe which features an event_base (must) provide.

   Because of OS limitations, not every Libevent backend supports every
   possible feature.  You can use this type with
   event_config_require_features() to tell Libevent to only proceed if your
   event_base implements a given feature, and you can receive this type from
   event_base_get_features() to see which features are available.
*/
enum event_method_feature {
    /** Require an event method that allows edge-triggered events with EV_ET. */
    EV_FEATURE_ET = 0x01,
    /** Require an event method where having one event triggered among
     * many is [approximately] an O(1) operation. This excludes (for
     * example) select and poll, which are approximately O(N) for N
     * equal to the total number of possible events. */
    EV_FEATURE_O1 = 0x02,
    /** Require an event method that allows file descriptors as well as
     * sockets. */
    EV_FEATURE_FDS = 0x04,
    /** Require an event method that allows you to use EV_CLOSED to detect
     * connection close without the necessity of reading all the pending data.
     *
     * Methods that do support EV_CLOSED may not be able to provide support on
     * all kernel versions.
     **/
    EV_FEATURE_EARLY_CLOSE = 0x08
};

/**
   A flag passed to event_config_set_flag().

    These flags change the behavior of an allocated event_base.

    @see event_config_set_flag(), event_base_new_with_config(),
       event_method_feature
 */
enum event_base_config_flag {
	/** Do not allocate a lock for the event base, even if we have
	    locking set up.

	    Setting this option will make it unsafe and nonfunctional to call
	    functions on the base concurrently from multiple threads.
	*/
	EVENT_BASE_FLAG_NOLOCK = 0x01,
	/** Do not check the EVENT_* environment variables when configuring
	    an event_base  */
	EVENT_BASE_FLAG_IGNORE_ENV = 0x02,
	/** Windows only: enable the IOCP dispatcher at startup

	    If this flag is set then bufferevent_socket_new() and
	    evconn_listener_new() will use IOCP-backed implementations
	    instead of the usual select-based one on Windows.
	 */
	EVENT_BASE_FLAG_STARTUP_IOCP = 0x04,
	/** Instead of checking the current time every time the event loop is
	    ready to run timeout callbacks, check after each timeout callback.
	 */
	EVENT_BASE_FLAG_NO_CACHE_TIME = 0x08,

	/** If we are using the epoll backend, this flag says that it is
	    safe to use Libevent's internal change-list code to batch up
	    adds and deletes in order to try to do as few syscalls as
	    possible.  Setting this flag can make your code run faster, but
	    it may trigger a Linux bug: it is not safe to use this flag
	    if you have any fds cloned by dup() or its variants.  Doing so
	    will produce strange and hard-to-diagnose bugs.

	    This flag can also be activated by setting the
	    EVENT_EPOLL_USE_CHANGELIST environment variable.

	    This flag has no effect if you wind up using a backend other than
	    epoll.
	 */
	EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST = 0x10,

	/** Ordinarily, Libevent implements its time and timeout code using
	    the fastest monotonic timer that we have.  If this flag is set,
	    however, we use less efficient more precise timer, assuming one is
	    present.
	 */
	EVENT_BASE_FLAG_PRECISE_TIMER = 0x20
};

/**
   Enters a required event method feature that the application demands.

   Note that not every feature or combination of features is supported
   on every platform.  Code that requests features should be prepared
   to handle the case where event_base_new_with_config() returns NULL, as in:
   
     event_config_require_features(cfg, EV_FEATURE_ET);
     base = event_base_new_with_config(cfg);
     if (base == NULL) {
       // We can't get edge-triggered behavior here.
       event_config_require_features(cfg, 0);
       base = event_base_new_with_config(cfg);
     }
   
@param cfg the event configuration object @param feature a bitfield of one or more event_method_feature values. Replaces values from previous calls to this function. @return 0 on success, -1 on failure. @see event_method_feature, event_base_new_with_config() */
EVENT2_EXPORT_SYMBOL int event_config_require_features(struct event_config *cfg, int feature); /** * Sets one or more flags to configure what parts of the eventual event_base * will be initialized, and how they'll work. * * @see event_base_config_flags, event_base_new_with_config() **/ EVENT2_EXPORT_SYMBOL int event_config_set_flag(struct event_config *cfg, int flag);

调用 event_config_avoid_method()可以通过名字让 libevent 避免使用特定的可用后端 。 调用 event_config_require_feature()让 libevent 不使用不能提供所有指定特征的后端。 调用 event_config_set_flag()让 libevent 在创建 event_base 时设置一个或者多个将在下面介绍的运行时标志。
event_config_require_features()可识别的特征值有:

  • EV_FEATURE_ET:要求支持边沿触发的后端
  • EV_FEATURE_O1:要求添加、删除单个事件,或者确定哪个事件激活的操作是O(1)复杂度的后端
  • EV_FEATURE_FDS:要求支持任意文件描述符,而不仅仅是套接字的后端

event_config_set_flag()可识别的选项值有:

  • EVENT_BASE_FLAG_NOLOCK :不要为 event_base 分配锁。设置这个选项可以为 event_base 节省一点用于锁定和解锁的时间,但是让在多个线程中访问event_base 成为不安全的。
  • EVENTBASE_FLAG_IGNORE_ENV :选择使用的后端时,不要检测 EVENT* 环境变量。使用这个标志需要三思:这会让用户更难调试你的程序与 libevent 的交互。
  • EVENT_BASE_FLAG_STARTUP_IOCP:仅用于 Windows,让 libevent 在启动时就 启用任何必需的 IOCP 分发逻辑,而不是按需启用。
  • EVENT_BASE_FLAG_NO_CACHE_TIME :不是在事件循环每次准备执行超时回调时 检测当前时间,而是在每次超时回调后进行检测。注意:这会消耗更多的CPU时间。
  • EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST :告诉 libevent ,如果决定使 用epoll后端,可以安全地使用更快的基于changelist 的后端。epoll-changelist后端可以 在后端的分发函数调用之间,同样的 fd 多次修改其状态的情况下,避免不必要的系统 调用。但是如果传递任何使用 dup()或者其变体克隆的 fd 给 libevent,epoll-changelist 后端会触发一个内核 bug,导致不正确的结果。在不使用 epoll 后端的情况下,这个标 志是没有效果的。也可以通过设置
  • EVENT_EPOLL_USE_CHANGELIST 环境变量来 打开 epoll-changelist 选项。

上述操作 event_config 的函数都在成功时返回0,失败时返回-1。

设置 event_config,请求 OS 不能提供的后端是很容易的 。比如说,对于 libevent2.0.1-alpha, 在 Windows 中是没有 O(1)后端的;在 Linux 中也没有同时提供EV_FEATURE_FDS 和 EV_FEATURE_O1 特征的后端。如果创建了 libevent不能满足的配置, event_base_new_with_config ()会返回 NULL。

检查event_base后端

有时候需要检查 event_base 支持哪些特征,或者当前使用哪种方法。

/**
   Gets all event notification mechanisms supported by Libevent.

   This functions returns the event mechanism in order preferred by
   Libevent.  Note that this list will include all backends that
   Libevent has compiled-in support for, and will not necessarily check
   your OS to see whether it has the required resources.

   @return an array with pointers to the names of support methods.
     The end of the array is indicated by a NULL pointer.  If an
     error is encountered NULL is returned.
*/
EVENT2_EXPORT_SYMBOL
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 运行的时候,操作系统可能 不能支持所有方法。比如说,可能 OS X 版本中的 kqueue 的 bug太多,无法使用。

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()返回 event_base 支持的特征的比特掩码。

实例:

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 之后,使用 event_base_free()进行释放。

/**
  Deallocate all memory associated with an event_base, and free the base.

  Note that this function will not close any fds or free any memory passed
  to event_new as the argument to callback.

  If there are any pending finalizer callbacks, this function will invoke
  them.

  @param eb an event_base to be freed
 */
EVENT2_EXPORT_SYMBOL
void event_base_free(struct event_base *);

注意:这个函数不会释放当前与 event_base 关联的任何事件,或者关闭他们的套接字, 或者释放任何指针。

event_base优先级

libevent支持为事件设置多个优先级。然而, event_base默认只支持单个优先级。可以调用 event_base_priority_init()设置 event_base 的优先级数目。

/**
  Set the number of different event priorities

  By default Libevent schedules all active events with the same priority.
  However, some time it is desirable to process some events with a higher
  priority than others.  For that reason, Libevent supports strict priority
  queues.  Active events with a lower priority are always processed before
  events with a higher priority.

  The number of different priorities can be set initially with the
  event_base_priority_init() function.  This function should be called
  before the first call to event_base_dispatch().  The
  event_priority_set() function can be used to assign a priority to an
  event.  By default, Libevent assigns the middle priority to all events
  unless their priority is explicitly set.

  Note that urgent-priority events can starve less-urgent events: after
  running all urgent-priority callbacks, Libevent checks for more urgent
  events again, before running less-urgent events.  Less-urgent events
  will not have their callbacks run until there are no events more urgent
  than them that want to be active.

  @param eb the event_base structure returned by event_base_new()
  @param npriorities the maximum number of priorities
  @return 0 if successful, or -1 if an error occurred
  @see event_priority_set()
 */
EVENT2_EXPORT_SYMBOL
int	event_base_priority_init(struct event_base *, int);

成功时这个函数返回 0,失败时返回 -1。base 是要修改的 event_base,n_priorities是要支持的优先级数目,这个数目至少是 1 。每个新的事件可用的优先级将从 0 (最高) 到 n_priorities-1(最低)。
常量 EVENT_MAX_PRIORITIES 表示 n_priorities 的上限。调用这个函数时为n_priorities 给出更大的值是错误的。

必须在任何事件激活之前调用这个函数,最好在创建 event_base 后立刻调用。

event_base和fork

不是所有事件后端都在调用 fork()之后可以正确工作。所以,如果在使用 fork()或者其 他相关系统调用启动新进程之后,希望在新进程中继续使用 event_base,就需要进行重新初始化。

/**
  Reinitialize the event base after a fork

  Some event mechanisms do not survive across fork.   The event base needs
  to be reinitialized with the event_reinit() function.

  @param base the event base that needs to be re-initialized
  @return 0 if successful, or -1 if some events could not be re-added.
  @see event_base_new()
*/
EVENT2_EXPORT_SYMBOL
int event_reinit(struct event_base *base);

成功时这个函数返回 0,失败时返回 -1。

实例:

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); /*...*/
}

你可能感兴趣的:(libevent,学习,c语言,libevent)