http://blog.csdn.net/mafuli007/article/details/7476014

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_base。Libevnet内置一个全局的event_base结构。多个线程应用中,如果多个线程都需要一个libevent事件循环,需要调用event_base_set修改事件结构基于的event_base。

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

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

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.      如监视的描述上发生了特定事件,把相应事件对象加入到活动事件队列。

libevent简单介绍的更多相关文章

  1. libevent简单介绍和使用

    <pre class="html" name="code">libevent接口的使用是简单easy的.关键还是一些其他技术须要深入了解.如epol ...

  2. C10K问题和Libevent库介绍

    http://blog.chinaunix.net/uid-20761674-id-75056.html 一.C10K的问题 C10K的问题在上个世纪90年代就被提出来了.大概的意思是当用户数超过1万 ...

  3. Cloudera impala简单介绍及安装具体解释

    一.Impala简单介绍 Cloudera Impala对你存储在Apache Hadoop在HDFS,HBase的数据提供直接查询互动的SQL.除了像Hive使用同样的统一存储平台,Impala也使 ...

  4. 服务器端IO模型的简单介绍及实现

    https://mp.weixin.qq.com/s?src=3&timestamp=1541726441&ver=1&signature=xPSye3v7miF7aVeLHb ...

  5. Memcached简单介绍

    Memcached简单介绍 简介:Memcached是一个自由开源的,高性能,分布式内存对象缓存系统.================================================= ...

  6. 服务器端IO模型的简单介绍及实现 阻塞 / 非阻塞 VS 同步 / 异步 内核实现的拷贝效率

    小结: 1.在多线程的基础上,可以考虑使用"线程池"或"连接池","线程池"旨在减少创建和销毁线程的频率,其维持一定合理数量的线程,并让空闲 ...

  7. [原创]关于mybatis中一级缓存和二级缓存的简单介绍

    关于mybatis中一级缓存和二级缓存的简单介绍 mybatis的一级缓存: MyBatis会在表示会话的SqlSession对象中建立一个简单的缓存,将每次查询到的结果结果缓存起来,当下次查询的时候 ...

  8. 利用Python进行数据分析(7) pandas基础: Series和DataFrame的简单介绍

    一.pandas 是什么 pandas 是基于 NumPy 的一个 Python 数据分析包,主要目的是为了数据分析.它提供了大量高级的数据结构和对数据处理的方法. pandas 有两个主要的数据结构 ...

  9. 利用Python进行数据分析(4) NumPy基础: ndarray简单介绍

    一.NumPy 是什么 NumPy 是 Python 科学计算的基础包,它专为进行严格的数字处理而产生.在之前的随笔里已有更加详细的介绍,这里不再赘述. 利用 Python 进行数据分析(一)简单介绍 ...

随机推荐

  1. NUnit Test Adapter----单元测试需要安装这个插件

    最近通过VS2012集成Nunit的测试用例,想直接在VS中查看结果,分析测试覆盖率:所以找到了NUnit Test Adapter插件:该插件下载地址: http://visualstudiogal ...

  2. 三,samba

    转载:http://www.cnblogs.com/phinecos/archive/2009/06/06/1497717.html 一. samba的安装: sudo apt-get insall  ...

  3. 数组和字典 swift

    var array = ["A","B"] var array2:[String] = ["A","B"] var ar ...

  4. jQuery ajax的traditional参数的作用

    一般的,可能有些人在一个参数有多个值的情况下,可能以某个字符分隔的形式传递,比如页面上有多个checkbox: ? 1 2 3 4 5 6 $.ajax{       url:"xxxx&q ...

  5. 目前国内外主流的linux发行版本

    1.linux其实是基于unix发展而来的,还有mac os也是类unix操作系统 2.目前主流的linux发行版本主要有:红帽系列(中国大陆,美洲地区,发源于美国),suse系列(欧洲地区流行,发源 ...

  6. 基于.net mvc的校友录(六、codefirst的使用以及班级模块的关键部分实现)

    通过EF将新用户存入数据库 这里,探讨一下如何使用EF的code first将数据存入数据库,以及如何对用户的密码进行md5加密与验证.下面是用户登陆的前台代码. @using (Html.Begin ...

  7. VS2010在C#头文件中添加文件注释的方法

    步骤: 1.VS2010 中找到安装盘符(本人安装目录在D盘,所以以D盘为例)D:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\I ...

  8. 小组开发项目NABC分析

    我们团队的开发项目为:重量解锁 是根据重力感应实现手机的解锁方式,在传统滑屏的基础上我们想增添新的形式,实现用户用一组动作就能实现手机解锁功能,更加方便,炫酷. NABC模型 1.N:我们的创意在使用 ...

  9. C++输出四则运算设计题的思路

    一,(1)题目避免重复:使用srand(seed)函数进行随机化,随seed的不同,可以产生不同的随机数二,(1)控制数量:输入变量n控制三,(1)控制是否有乘除:(chengchu=0,没有乘除:c ...

  10. Why Every Professional Should Consider Blogging

    转自http://www.pixelstech.net/article/1327829407-Why-Every-Professional-Should-Consider-Blogging ften ...