zoukankan      html  css  js  c++  java
  • libevent简单介绍

    1      简介

    主页:http://www.monkey.org/~provos/libevent/

    libevent是一个事件触发的网络库,适用于windows、Linux、bsd等多种平台,内部使用select、epoll、kqueue等系统调用管理事件机制。

    编译库代码,编译脚本会判断OS支持哪种类型的事件机制(select、epoll或kqueue),然后条件编译相应代码,供上层使用的接口仍然是保持统一的。

    libevent支持用户使用三种类型的事件,分别是网络IO、定时器、信号三种。定时器的数据结构使用最小堆(Min Heap),以提高效率。网络IO和信号的数据结构采用了双向链表(TAILQ)。在实现上主要有3种链表:EVLIST_INSERTED, EVLIST_ACTIVE, EVLIST_TIMEOUT,一个ev在这3种链表之间被插入或删除,处于EVLIST_ACTIVE链表中的ev最后将会被调度执行。

    有许多开源项目使用libevent,例如memcached。使用libevent,使得memcached可以适应多种操作系统。Libevent对底层异步函数提供了较薄封装,库本身没有消耗过多性能;另外,使用堆排序管理定时器队列,提供了较高的性能。

    2      使用介绍

    2.1   网络IO

    2.1.1  代码例子

    //事件回调处理函数

    Static void MyCallBack(const int fd, constshort which, void *arg)

    {

           If(EV_READ==which){

                  //读事件处理

    }

    ……

    }

    Int main(int argc, char** argv)

    {

           //初始化libevent

           structevent_base *pEventBase;

           pEventBase =event_init();

          

           intsock=socket(……);

          

    struct eventevent;

           event_set(&event , sock, EV_READ | EV_PERSIST,MyCallBack, (void*)0 );

     

           event_base_set(pEventBase, &event);

          

           event_add(&event, 0);

     

           event_base_loop(pEventBase, 0);

     

           Return0;

    }

    2.1.2  基本函数介绍

    event_init:初始化libevent库。

    event_set:赋值structevent结构。可以用event_add把该事件结构增加到事件循环,用event_del从事件循环中删除。支持的事件类型可以是下面组合:EV_READ(可读),  EV_WRITE(可写),EV_PERSIST(除非调用event_del,否则事件一直在事件循环中)。

     

    event_base_set:修改structevent事件结构所属的event_base为指定的event_baseLibevnet内置一个全局的event_base结构。多个线程应用中,如果多个线程都需要一个libevent事件循环,需要调用event_base_set修改事件结构基于的event_base

     

    event_add:增加事件到事件监控中。

    event_base_loop:事件循环。调用底层的selectpollepoll等,如监听事件发生,调用事件结构中指定的回调函数。

     

    2.2   定时器

    2.2.1  代码例子

    struct event g_clockevent;

    struct event_base *g_pEventBase;

    void clock_handler(const int fd, constshort which, void *arg)

    {    

                 

           staticbool initialized = false;

           if(initialized) {

                  evtimer_del(&g_clockevent);

           }

           else {

                  initialized= true;

           }

                 

           evtimer_set(&g_clockevent, clock_handler, (void*) 0);

          

           //定时器时间

           structtimeval t ;

           t.tv_sec=1;

           t.tv_usec=0;

          

           event_base_set(g_pEventBase, &me->m_clockevent);

           if(evtimer_add(&clock_handler, &t) == -1){           

                  return;

           }

          

           //自定义事件处理

           .....

    }

    int main(int argv, char** argc)

    {

           g_pEventBase=event_init();

           clock_handler(0,0,(void*)0);

           return0;

    }

    2.2.2  基本函数介绍

    evtimer_set: 设置定时器事件。

    evtimer_add: 增加定时器时间。

    3      源代码简介

    Libevent在底层select、pool、kqueue和epoll等机制基础上,封装出一致的事件接口。可以注册可读、可写、超时等事件,指定回调函数;当事件发生后,libevent调用回调函数,可以在回调函数里实现自定义功能。前面例子已经展现了如何使用libevent接口。

    本节探讨一下libevent实现机制。

    3.1   重要结构体

    struct eventop:对select/pool/epoll/kqueue等底层函数,按照该结构提供的接口方式,封装接口统一的函数。

    struct eventop {

           constchar *name;

           void*(*init)(struct event_base *);

           int(*add)(void *, struct event *);

           int(*del)(void*, struct event *);

           int(*dispatch)(struct event_base *, void *, struct timeval *);

           void(*dealloc)(struct event_base *, void *);

           /*set if we need to reinitialize the event base */

           intneed_reinit;

    };

    struct event_base:相当于一个事件池。一个线程一个。使用提供的API,把需要监控的事件结构加入到该事件池中。

    struct event_base {

           conststruct eventop *evsel;   //指向编译时选择的一个select/pool/epoll/kqueue接口封装对象。

           void*evbase;

           intevent_count;            /* counts numberof total events */

           intevent_count_active;  /* counts number ofactive events */

           intevent_gotterm;         /* Set to terminateloop */

           intevent_break;            /* Set toterminate loop immediately */

           /*active event management */

           structevent_list **activequeues; //活动事件队列

           intnactivequeues;

           /*signal handling info */

           structevsignal_info sig;

           structevent_list eventqueue;  //监听事件队列

           structtimeval event_tv;

           structmin_heap timeheap; //定时器时间堆

           structtimeval tv_cache;

    };

    线程事件循环使用底层机制异步监控事件。

    struct event:事件结构。

    struct event {

           TAILQ_ENTRY(event) ev_next;

           TAILQ_ENTRY(event) ev_active_next;

           TAILQ_ENTRY(event) ev_signal_next;

           unsignedint min_heap_idx;   /* for managingtimeouts */

           structevent_base *ev_base;  //事件输入的evnet_base

           intev_fd;

           shortev_events;

           shortev_ncalls;

           short*ev_pncalls;   /* Allows deletes incallback */

           structtimeval ev_timeout;

           intev_pri;             /* smaller numbers arehigher priority */

           void(*ev_callback)(int, short, void *arg);  //回调函数

           void*ev_arg;

           intev_res;             /* result passed toevent callback */

           intev_flags;

    };

    3.2   主要函数介绍

    按照使用libevnet库顺序,看一下相关函数做什么操作。

    3.2.1  event_init

    调用event_base_new,初始化struct event_base对象。

    event_base_new里做了如下工作:

    1、 申请内存

    2、 初始化定时器堆和事件队列

    3、 为event_base对象选择底层事件函数封装对象。根据编译选项,初始化eventops全局对象。该对象存放指向底层select/pool/epoll等功能的封装函数。

    4、 初始化活动队列。

    3.2.2  event_set

    初始化structevent对象。

    1、 把参数中指定初始化的事件对象的ev_base指向全局的current_base。

    2、 赋值回调函数、描述符、监视事件等变量。

    3.2.3  event_base_set

    把struct event对象指向的event_base对象赋值为指定的对象。

    event_set函数把event对象的ev_base指向全局的current_base,多线程环境下,如需要用自己的event_base对象,需要调用event_base_set重新指定event_base对象。

    3.2.4  event_add

    增加指定event到监控池里。

    1、 对于读、写、信号事件,调用封装的add函数,调用底层select/pool/epoll相关函数,增加到操作系统事件监控里。对于epoll,调用的是epoll_add函数。Epoll_add函数调用epoll_ctl添加事件监控,libevent使用水平触发方式。把监听时间加入到event_base的事件队列中。

    2、 对应定时器事件,加入到event_base的定时器最小堆里。

    3、 对信号事件,调用evsignal_add,加入事件处理队列中。

    3.2.5  event_base_loop

    事件循环,事件发生后,调用相应回调函数。

    1、 计算最近的超时时间:定时器最小堆按照超时时间排序,取最小的超时时间;如已有活动事件或指定不阻塞,超时时间为0。

    2、 调用dispatch。对epoll,对应epoll_dispatch函数。该函数调用epoll_wait监控指定事件。

    3、 把到了超时时间的时间加入到活动事件队列。从超时时间最小堆中依次取最小超时时间和当前时间比较,对小于/等于当前时间的事件,加入到活动事件队列。

    4、 循环调用活动事件队列中所有事件的回调函数。

    epoll_dispatch:

    1.      计算epoll_wait函数需要的超时时间,把时间转换成微妙。

    2.      如epoll_wait被信号中断,把相应信号对应的事件加入到活动事件队列。

    3.      如监视的描述上发生了特定事件,把相应事件对象加入到活动事件队列。

  • 相关阅读:
    DFS(White-Gray-Black)
    Recursive Depth first search graph(adj matrix)
    TED_Topic1:Why we need to rethink capitalism
    Eng1—English daily notes
    R2—《R in Nutshell》 读书笔记(连载)
    R1(上)—R关联规则分析之Arules包详解
    R1(下)—数据挖掘—关联规则理论介绍与R实现
    R0—New packages for reading data into R — fast
    Tools0—Word2013发布博客到博客园的详细方法介绍
    day6 类
  • 原文地址:https://www.cnblogs.com/Kobe10/p/6378537.html
Copyright © 2011-2022 走看看