一:运行loop      

一旦一些events在event_base注册之后(下一节会讨论如何创建和注册events),就可以使Libevent等待events,并且在events准备好时能够通知你。

#define EVLOOP_ONCE             0x01

#define EVLOOP_NONBLOCK         0x02

#define EVLOOP_NO_EXIT_ON_EMPTY 0x04

int event_base_loop(struct event_base *base, int flags);

默认情况下,event_base_loop()会在event_base上一直运行,直到其上已经没有注册的events了。运行loop时,它会重复检查那些已经注册的events是否触发了(比如,一个读event的文件描述符变得可读,或者后一个超时event已经超时)。一旦触发,该函数会将这些触发的events标记为active,并且开始运行回调函数。

可以通过设置一个或多个flag参数,来改变event_base_loop()函数的行为。如果设置了EVLOOP_ONCE,那么loop将会一直等待,直到一些events变为active,然后运行这些激活的events的回调函数,直到运行完所有激活的events为止,最后函数返回。如果设置了EVLOOP_NONBLOCK标志,则该函数不会等待events变为触发,它仅仅检查是否有事件准备好了,然后运行他们的回调函数,最后函数返回。

通常情况下,loop只有在没有pending或active状态的events时,才会退出。可以通过设置EVLOOP_NO_EXIT_ON_EMPTY标志来改变这种行为。比如,如果通过其他线程来添加events,并且设置了该标志,那么loop将会一直运行,直到event_base_loopbreak()或event_base_loopexit()被调用,或者发生某些错误。

event_base_loop函数返回0表示正常退出,返回-1表示后端方法发生了错误。返回1表示已经没有pending或active状态的events了。

为了帮助理解,下面是event_base_loop算法的伪代码实现:

while(any events are registered with the loop,

or EVLOOP_NO_EXIT_ON_EMPTY was set) {

if (EVLOOP_NONBLOCK was set, or any eventsare already active)

If any registered events have triggered, mark them active.

else

Wait until at least one event has triggered, and mark it active.

for (p = 0; p < n_priorities; ++p) {

if (any event with priority of p isactive) {

Run all active events with priorityof p.

break; /* Do not run any events of aless important priority */

}

}

if (EVLOOP_ONCE was set or EVLOOP_NONBLOCKwas set)

break;

}

方便起见,也可以使用下面的接口:

intevent_base_dispatch(struct event_base *base);

该函数等价于无标志的event_base_loop()函数。因此,直到没有注册的events,或者调用了event_base_loopbreak()、 event_base_loopexit(),该函数才会返回。

二:停止loop

如果希望在所有events移除之前,就停止event loop的运行,有两个略有不同的接口可以调用:

int event_base_loopexit(struct event_base *base,  const struct timeval *tv);

int event_base_loopbreak(struct event_base *base);

event_base_loopexit()函数,使得event_base在经过了给定的超时时间之后,停止运行loop。如果tv参数为NULL,则event_base会立即停止loop。如果event_base正在运行active events的回调函数,则只有在运行完所有的回调之后,才停止loop。

event_base_loopbreak()函数,使event_base立即退出loop。它与event_base_loopexit(base,NULL)不同之处在于,如果event_base当前正在运行任何激活events的回调函数,则会在当前的回调函数返回之后,就立即退出。

注意,当event loop没有运行时,event_base_loopexit(base, NULL)和
event_base_loopbreak(base)的行为是不同的:loopexit使下一轮event loop在下一轮回调运行之后立即停止(就像设置了EVLOOP_ONCE一样),而loopbreak仅仅停止当前loop的运行,而且在event
loop未运行时没有任何效果。

上述两个方法在成功是返回0, 失败时返回-1,。

立即停止:

#include <event2/event.h>

/*Here's a callback function that calls loopbreak */

void cb(int sock, short what, void *arg)

{

struct event_base *base = arg;

event_base_loopbreak(base);

}

void main_loop(struct event_base *base, evutil_socket_t watchdog_fd)

{

struct event *watchdog_event;

/* Construct a new event to triggerwhenever there are any bytes to

read from a watchdog socket.  When that happens, we'll call the

cb function, which will make the loop exitimmediately without

running any other active events at all.

*/

watchdog_event = event_new(base, watchdog_fd, EV_READ, cb, base);

event_add(watchdog_event, NULL);

event_base_dispatch(base);

}

运行event loop10秒钟,然后退出。

#include <event2/event.h>

void run_base_with_ticks(struct event_base *base)

{

struct timeval ten_sec;

ten_sec.tv_sec = 10;

ten_sec.tv_usec = 0;

/* Now we run the event_base for a series of10-second intervals, printing

"Tick" after each.  For a much better way to implement a10-second

timer, see the section below aboutpersistent timer events. */

while (1) {

/* This schedules an exit ten seconds fromnow. */

event_base_loopexit(base, &ten_sec);

event_base_dispatch(base);

puts("Tick");

}

}

有些时候需要知道event_base_dispatch()或event_base_loop()的调用是正常退出,还是因为调用了event_base_loopexit()或event_base_break()而退出。可以使用下面的函数判断是否调用了loopexit或break:

int event_base_got_exit(struct event_base *base);

int event_base_got_break(structevent_base *base)

上述函数,如果loop的停止是因为调用了event_base_loopexit()或event_base_break() ,则会返回True。否则,会返回False。他们的值会在下次启动eventloop时被重置。

上述函数在<event2/event.h>中声明。

三:重新检查events

一般情况下,Libevent会检查events,然后从高优先级的激活events开始运行,然后再次检查events。有时,你可能希望在运行完当前运行的回调函数之后,告知Libevent重新检查events。与event_base_loopbreak()类似,这可以通过调用event_base_loopcontinue()实现。

int event_base_loopcontinue(struct event_base *);

如果当前没有运行events的回调函数的话,则该函数没有任何效果。

四:检查内部时间缓存(?)

有时候可能需要在event回调函数内部,得到当前时间的近似视图,而且不希望使用gettimeoufday(可能是因为OS将gettimeofday()作为系统调用实现,而你希望避免系统调用的开销)。

在回调函数内部,可以在开始执行这一轮的回调时,得到Libevent的当前时间的视图:

int  event_base_gettimeofday_cached(struct  event_base *base,  struct  timeval*tv_out);

如果event_base正在执行回调函数的话,那么event_base_gettimeofday_cached()函数会将tv_out参数设置为缓存的时间。否则,它会调用evutil_gettimeofday()得到当前实际的时间。该函数成功返回0,失败返回负数。

注意,因为当Libevent在开始执行回调的时候时间值才会被缓存,所以这个值会有一点不精确。如果回调执行很长时间,这个值将非常不精确。

为了使缓存能够立即刷新,可以调用:

int event_base_update_cache_time(struct event_base *base);

该函数在成功时返回0,失败时返回-1。而且在event_base没有运行eventloop时无效。

五:转储event_base状态

void event_base_dump_events(struct event_base *base, FILE *f);

为了调试程序的方便,有时会需要得到所有关联到event_base的events的列表以及他们的状态。调用event_base_dump_events()可以讲该列表输出到文件f中。

得到的列表格式是人可读的形式,将来版本 的Libevent可能会改变其格式。

六: event_base中的每个event运行同一个回调函数

typedef int (*event_base_foreach_event_cb)(const struct event_base *, const structevent *, void *);

int event_base_foreach_event(struct event_base *base,

event_base_foreach_event_cb fn,

void *arg);

调用函数event_base_foreach_event(),遍历运行与event_base关联的每一个active 或pending的event。每一个event都会运行一次所提供的回调函数,运行顺序是未指定的。event_base_foreach_event()函数的第三个参数将会传递给回调函数的第三个参数。

回调函数必须返回0,才能继续执行遍历。否则会停止遍历。回调函数最终的返回值,就是event_base_foreach_function函数的返回值。

回调函数不可修改它接收到的events参数,也不能为event_base添加或删除events,或修改关联到event_base上的任何events。否则将会发生未定义的行为,甚至是崩溃。

在调用event_base_foreach_event期间,event_base的锁会被锁住。这样就会阻止其他线程使用该event_base,因而需要保证提供的回调函数不会运行太长时间。

七:废弃的loop函数

前面已经讨论过,老版本的Libevent 具有“当前”event_base这样的全局概念。本文讨论的某些event loop函数具有操作当前event_base的变体函数。除了没有base参数外,这些函数跟当前新版本函数的行为相同。

Current function

Obsolete current-base version

event_base_dispatch()

event_dispatch()

event_base_loop()

event_loop()

event_base_loopexit()

event_loopexit()

event_base_loopbreak()

event_loopbreak()

注意,2.0版本之前的event_base是不支持锁的,所以这些老版本的函数并不是完全线程安全的:不允许在执行event loop的线程之外的其他线程中调用_loopbreak()或者_loopexit()函数。

原文:http://www.wangafu.net/~nickm/libevent-book/Ref3_eventloop.html

Libevent:4event loop的更多相关文章

  1. Libevent:5events相关

    Libevents的基本操作单元是event,每一个event代表了一些条件的集合,这些条件包括: 文件描述符已经准备好读或写 文件描述符正在变为就绪,准备好读或写(仅限于边沿触发) 超时事件 信号发 ...

  2. Libevent:1前言

    一:libevent概述: libevent是一个用来编写快速.可移植.非阻塞IO程序的库,它的设计目标是:可移植性.高效.可扩展性.便捷. libevent包含下列组件: evutil:对不同平台下 ...

  3. HTML Standard系列:Event loop、requestIdleCallback 和 requestAnimationFrame

    HTML Standard系列:Event loop.requestIdleCallback 和 requestAnimationFrame - 掘金 https://juejin.im/post/5 ...

  4. Libevent:9Evbuffers缓存IO的实用功能

    Libevent的evbuffer功能实现了一个字节队列,优化了在队列尾端增加数据,以及从队列前端删除数据的操作. Evbuffer用来实现缓存网络IO中的缓存部分.它们不能用来在条件发生时调度IO或 ...

  5. Libevent:8Bufferevents高级主题

    本章描述的是Libevent的bufferevent实现的一些高级特性,这对于普通应用来说并非必须的.如果你只是学习如何使用bufferevent,则应该跳过本章去阅读evbuffer的章节. 一:成 ...

  6. Libevent:3创建event_base

    在使用Libevent函数之前,需要分配一个或多个event_base结构.每一个event_base都持有一个events的集合,并且可以检测那些events是激活的. 如果设置event_base ...

  7. JavaScript 运行机制详解:Event Loop

    参考地址:http://www.ruanyifeng.com/blog/2014/10/event-loop.html 一.为什么JavaScript是单线程? JavaScript语言的一大特点就是 ...

  8. JavaScript:event loop详解

    之前已经有两篇随笔提到了event loop,一篇是事件机制,一篇是tasks和microtasks,但是里面的event loop都是文字描述,很难说细,逻辑也只是简单的提了一遍.其实之前也是通过阮 ...

  9. Libevent:11使用Libevent的DNS上层和底层功能

    Libevent提供了一些API用来进行DNS域名解析,并且提供了实现简单DNS服务器的能力. 本章首先描述域名解析的上层功能,然后介绍底层功能及服务器功能. 注意:Libevent的当前DNS客户端 ...

随机推荐

  1. Linux程序包管理初步-rpm的使用

    在Linux系统上,一般而言,对于程序包管理器来说分为三类: debian:dpt,dpkg;             (程序包后缀.deb) rhel:rpm (程序包后缀.rpm) suse:rp ...

  2. Java是如何实现跨平台的

    一.Java是如何实现跨平台的 1.我们编写的Java源码,编译后会生成一种 .class 文件,称为字节码文件 2.Java虚拟机JVM就是负责将字节码文件翻译成特定平台下的机器码然后运行.也就是说 ...

  3. python基础--函数的命名空间and作用域

    函数对象:函数是第一类对象,函数名指向的值是可以被当作参数进行传递的 1.函数名可以被传递 2.函数名可以被当作参数传递给其它函数 3.函数名可以被当作函数的返回值 4.函数名可以被当作容器类型的参数 ...

  4. mysql8忘记密码的解决方法

    mysql8忘记密码的解决方法 1.管理员身份打开cmd,进入dos 2.停止mysql服务 命令:net stop mysql 3.无密码启动 命令:mysqld --console --skip- ...

  5. linux引导和登录/注销配置文件

    引导和登录/注销 /etc/issue & /etc/issue.net 这些文件由 mingetty(和类似的程序)读取,用来向从终端(issue)或通过 telnet 会话(issue.n ...

  6. 洛谷P1263 宫廷守卫

    P1263 宫廷守卫 题目描述 从前有一个王国,这个王国的城堡是一个矩形,被分为M×N个方格.一些方格是墙,而另一些是空地.这个王国的国王在城堡里设了一些陷阱,每个陷阱占据一块空地. 一天,国王决定在 ...

  7. 【模板】倍增LCA [2017年5月计划 清北学堂51精英班 Day3]

    P3379 [模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询 ...

  8. Codeforces 1150E(树、线段树)

    要点 括号序列平衡度即树深度的性质 相当于中序遍历,则两点间最浅的地方即是LCA的性质 线段树维护\(d(a) + d(c) - 2*d(lca(a,c))\),一层层剥,思考维护这个量需要什么,结果 ...

  9. php pdo操作数据库的方法

    PDO 安装 你可以通过 PHP 的 phpinfo() 函数来查看是否安装了PDO扩展. 1.在 Unix /linux系统上安装 PDO 在Unix上或Linux上你需要添加以下扩展: exten ...

  10. 【JZOJ3299】【SDOI2013】保护出题人 三分+凸壳

    题面 ​出题人铭铭认为给SDOI2012 出题太可怕了,因为总要被骂,于是他又给SDOI2013 出题了. 参加SDOI2012 的小朋友们释放出大量的僵尸,企图攻击铭铭的家.而你作为SDOI2013 ...