EventLoop

active

  何为活跃就是事件就绪,如果事件就绪 event循坏会把该事件标志为就绪。&emspl libevent检测循环事件的时候,先执行最高优先级的活跃事件,执行完毕后,libevent再次检测event事件,就这样一直循环。

可设置的event循坏 int event_base_loop(struct event_base *base, int flags)

#define EVLOOP_ONCE             0x01   // 代表就循坏1次
#define EVLOOP_NONBLOCK         0x02
#define EVLOOP_NO_EXIT_ON_EMPTY 0x04

  第一个选项,代表,这个函数会一直循坏等待事件就绪,然后把就绪的事件跑完后返回。
  第二个选项,不会阻塞,调用的时候如果事件活跃就调用回调函数,如果没有就返回。
  第三个选项,代表一直死循坏,除非该 event_base 调用 退出函数来退出。event_base_loopbreak / exit 。
  返回值 0 正常, -1 有error,1 代表非阻塞时候的事件未就绪的返回。

event_base_loop算法
while (any events are registered with the loop,
        或者 设置EVLOOP_NO_EXIT_ON_EMPTY  ) {

    if (EVLOOP_NONBLOCK was set, or any events are 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循坏只有上面的代码标记了活跃,下面才会调对应
       event的回调函数
    /***************************************************/
    for (p = 0; p < n_priorities; ++p) {
       if (any event with priority of p is active) {
          Run all active events with priority of p.
          break; /* Do not run any events of a less important priority */
       } 
    }
    /********最低优先级将不会跑它的回调函数***************/
    if (EVLOOP_ONCE was set or EVLOOP_NONBLOCK was set)
       break;
}

默认的event循坏event_base_dispatch

  它跟没有设置flag的event_base_loop一样,它会一直循坏当没有任何注册事件(即没有任何 pending状态的事件时才会 退出循坏 )或者调用了退出函数,它才退出。
  所谓没有任何注册事件,指要么所有event都是非持久化的 (没设置 EV_PERSIST) 然后其回调函数都被调用了,所有 event_base中并没有 pending态的event,要么就是 通过event_del 把 所有 event 事件从 event_base都删除了造成没有任何pending态的event。
  当该event_base没有 pending态的 event,此循环就会退出。

循坏退出函数

int event_base_loopexit(struct event_base *base,  const struct timeval *tv)  
int event_base_loopbreak(struct event_base *base);
返回值 成功0  失败 -1

第一个函数中 tv 是时间,定时用的,如果时间到了则执行event_base_loopexit ,传NULL立即执行event_base_loopexit 函数。
这俩个函数都会使循坏退出,但是区别是 event_base_exit 不会立即退出,它至少跑一轮循坏,就像设置了event_once选项一样。(如果正在跑活跃事件,就把当前所有活跃的跑一遍)

event_base_loopbreak 则不同,如果正在执行回调函数,执行完当前回调函数就退出,不会跑一轮,如果 event_base 没有活跃事件则立即停止循坏。 若event_base 没有循坏,就像没有调用过退出函数一样。

查看是调用那个函数退出

有时候我们想知道,我们是正常调用event_base_dispatch 或者 event_base_loop 正常退出,还是通过调用 event_base_loopexit() 或者 event_base_loopbreak() 退出,可以通过调用下面这俩个函数知道,从命名就知道调用了相应的退出函数,下面的函数就会返回True。这些检测值将在下次loop是重置。

  • int event_base_got_exit(struct event_base *base)
  • int event_base_got_break(structevent_base *base)
event_base_loopcontinue

  当我们有需求想要在调用完本次回调函数后重新执行loop循环,通知event_base重新进行loop循环

获取时间

  如果我们有一个需求,就是在调用回调函数的过程中,先知道当前时间,可能我们需要知道当前时间,然后把它返回给另一台机器。那么我们可以在里面调用gettimeofday这个系统调用函数,但是由于它是系统调用函数,所以我们应该避免多次调用它,所以Libevent为我们封装了俩个函数来查看当前时间

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

   这个函数的 timeval的值是在 call_back函数刚开始调用就保存(cached)起来。所以分俩种情况

  1. event 没有在 call_back函数中,libevent会转调 evutil_gettimeofday函数来获取当前时间
  2. event 在call_back函数中,那么这个时候就会返回刚开始执行的时候保存的这个timeval的值

  因为这种机制的存在,所以回调函数执行过程越久它的误差越大

int event_base_update_cache_time(struct event_base *base)

  这个函数就是来弥补上面这个误差的,通过调用这个函数,可以强制libevent刷新cached的时间,如果这个event 没有注册到当前的event循环中没有任何影响。这个函数版本是 2.1.1-alpha

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

  如果我们想知道所有event的注册信息和它注册后的状态信息,那么可以调用这个函数,它是用来方便debug的

老的循环结构

在Libevent 2.0 之前,Libevent不支持lock,所以调用 .loopexit .loopbreak函数不是线程安全的,除非这个线程正在 处理这个eventloop。

阅读更多
个人分类: Libevent
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭