和Libevent相似,Libev是一个高性事件驱动框架,据说性能比Libevent要高,bug比Libevent要少。Libev只是一个事件驱动框架,不是网络库,因为它的内部并没有任何socket编程代码。支持的事件驱动机制包括:

select
poll
epoll
kqueue
Solaris-specific event port mechanisms

支持的事件类型也很多,下面会全部列出。

官方首页地址:http://software.schmorp.de/pkg/libev.html

安装方法:apt-get install libev-dev

官方文档的第一个例程:

// a single header file is required
#include <ev.h> #include <stdio.h> // for puts // every watcher type has its own typedef'd struct
// with the name ev_TYPE
ev_io stdin_watcher;
ev_timer timeout_watcher; // all watcher callbacks have a similar signature
// this callback is called when data is readable on stdin
static void
stdin_cb (EV_P_ ev_io *w, int revents)
{
puts ("stdin ready");
// for one-shot events, one must manually stop the watcher
// with its corresponding stop function.
ev_io_stop (EV_A_ w); // this causes all nested ev_run's to stop iterating
ev_break (EV_A_ EVBREAK_ALL);
} // another callback, this time for a time-out
static void
timeout_cb (EV_P_ ev_timer *w, int revents)
{
puts ("timeout");
// this causes the innermost ev_run to stop iterating
ev_break (EV_A_ EVBREAK_ONE);
} int
main (void)
{
// use the default event loop unless you have special needs
struct ev_loop *loop = EV_DEFAULT; // initialise an io watcher, then start it
// this one will watch for stdin to become readable
ev_io_init (&stdin_watcher, stdin_cb, /*STDIN_FILENO*/ , EV_READ);
ev_io_start (loop, &stdin_watcher); // initialise a timer watcher, then start it
// simple non-repeating 5.5 second timeout
ev_timer_init (&timeout_watcher, timeout_cb, 5.5, .);
ev_timer_start (loop, &timeout_watcher); // now wait for events to arrive
ev_run (loop, ); // break was called, so exit
return ;
}

这些基于事件的库的使用方法都大同小异:首先建立一个event loop,然后建立需要观察的event,设置好回调函数,将event加入到event loop中,最后run loop。以上程序关注了两类事件:

  1. i/o事件,用ev_io结构体表示。
  2. timer事件,用ev_timer结构体表示。

事件类型的不同,所需的结构体类型也不同,对应关系如下所示:

ev_io                 // IO可读可写
ev_stat // 文件属性变化
ev_signal // 信号处理
ev_timer // 相对定时器
ev_periodic // 绝对定时器
ev_child // 子进程状态变化
ev_fork // fork事件
ev_cleanup // event loop退出触发事件
ev_idle // event loop空闲触发事件
ev_embed // 嵌入另一个后台循环
ev_prepare // event loop之前事件
ev_check // event loop之后事件
ev_async // 线程间异步事件

关于每个事件的具体含义,官方文档的WATCHER TYPES部分给出了详细的说明,需要时自行查阅即可。

首先分析一下struct ev_loop,即event loop,一个线程只能有一个struct ev_loop,它的定义如下所示:

#if EV_MULTIPLICITY
/* 支持多线程时需要定义ev_loop类 */
struct ev_loop
{
ev_tstamp ev_rt_now;
#define ev_rt_now ((loop)->ev_rt_now)
#define VAR(name,decl) decl;
#include "ev_vars.h"
#undef VAR
};
#include "ev_wrap.h" static struct ev_loop default_loop_struct;
EV_API_DECL struct ev_loop *ev_default_loop_ptr = ; /* needs to be initialised to make it a definition despite extern */ #else
/* 单线程时所有变量都是全局变量 */
EV_API_DECL ev_tstamp ev_rt_now = ; /* needs to be initialised to make it a definition despite extern */
#define VAR(name,decl) static decl;
#include "ev_vars.h"
#undef VAR static int ev_default_loop_ptr; #endif

条件编译宏EV_MULTIPLICITY在编译程序时判断程序是否为多线程。当程序为多线程时,也就是上面程序的if分支,由于存在不同的ev_loop,那么就需要struct ev_loop这个结构体进行封装了。当程序为单线程时,也就是上面程序的else分支,整个程序只有唯一的一个ev_loop,它将作为全局变量被所有函数使用。头文件ev_vars.h中定义了各种宏,封装在ev_loop中相当于ev_loop的成员变量,如下所示:

struct ev_loop
{
ev_tstamp ev_rt_now;
#define ev_rt_now ((loop)->ev_rt_now)
ev_tstamp now_floor
ev_tstamp mn_now
ev_tstamp rtmn_diff
...
};

而else分支的ev_vars.h没有封装在任何结构体中,因此会声明一大堆全局变量,如下所示:

static ev_tstamp now_floor
static ev_tstamp mn_now
static ev_tstamp rtmn_diff
...

经过深入分析,发现EV_MULTIPLICITY等于1,所以之后的源码分析都是假设EV_MULTIPLICITY=1.

Libev中许多函数定义的形式都是这样的:

static void
timeout_cb (EV_P_ ev_timer *w, int revents)

EV_P_也是为了多线程而存在的,它的定义如下所示:

/* support multiple event loops? */
#if EV_MULTIPLICITY
struct ev_loop;
# define EV_P struct ev_loop *loop /* a loop as sole parameter in a declaration */
# define EV_P_ EV_P, /* a loop as first of multiple parameters */
# define EV_A loop /* a loop as sole argument to a function call */
# define EV_A_ EV_A, /* a loop as first of multiple arguments */
# define EV_DEFAULT_UC ev_default_loop_uc_ () /* the default loop, if initialised, as sole arg */
# define EV_DEFAULT_UC_ EV_DEFAULT_UC, /* the default loop as first of multiple arguments */
# define EV_DEFAULT ev_default_loop () /* the default loop as sole arg */
# define EV_DEFAULT_ EV_DEFAULT, /* the default loop as first of multiple arguments */
#else
# define EV_P void
# define EV_P_
# define EV_A
# define EV_A_
# define EV_DEFAULT
# define EV_DEFAULT_
# define EV_DEFAULT_UC
# define EV_DEFAULT_UC_
# undef EV_EMBED_ENABLE
#endif

宏EV_P_最终等于struct ev_loop *loop。当系统支持多线程,每个线程都有一个struct ev_loop时,函数需要区分不同的struct ev_loop,这是就是通过这个宏EV_P_传入某个具体的struct ev_loop。也就是说,当程序为单线程时,函数最终声明为:

static void
timeout_cb (ev_timer *w, int revents)

Libev操纵唯一的一个全局struct ev_loop。当程序支持多线程时,函数最终声明为:

static void
timeout_cb (struct ev_loop *loop, ev_timer *w, int revents)

Libev根据传入的loop操纵对应的struct ev_loop。

参考:

http://c4fun.cn/blog/2014/03/06/libev-study/

http://my.oschina.net/u/917596/blog/176658

Libev学习笔记1的更多相关文章

  1. libev学习笔记

    转 libev的使用--结合Socket编程 作者:cxy450019566 之前自己学过一些libev编程的基础,这次写压测刚好用上了,才算真正动手写了些东西,在这里做一些总结.写这篇文章是为了用浅 ...

  2. Libev学习笔记4

    这一节首先分析Libev的定时器部分,然后分析signal部分. 对定时器的使用主要有两个函数: ev_timer_init (&timeout_watcher, timeout_cb, .) ...

  3. Libev学习笔记3

    设置完需要监听的事件之后,就开始event loop了.在Libev中,该工作由ev_run函数完成.它的大致流程如下: int ev_run (EV_P_ int flags) { do { /* ...

  4. Libev学习笔记2

    这一节根据官方文档给出的简单示例,深入代码内部,了解其实现机制.示例代码如下: int main (void) { struct ev_loop *loop = EV_DEFAULT; ev_io_i ...

  5. libev 学习使用

    libev 简单的I/O库.  a high performance full featured event loop written in c libev 的大小也比 libevent 小得多并且自 ...

  6. js学习笔记:webpack基础入门(一)

    之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...

  7. PHP-自定义模板-学习笔记

    1.  开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2.  整体架构图 ...

  8. PHP-会员登录与注册例子解析-学习笔记

    1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...

  9. 2014年暑假c#学习笔记目录

    2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...

随机推荐

  1. apache-tomcat-7 设置最大上传.war文件大小[zhuan]

    在利用tomcat自带的主机管理页面进行WAR包部署的时候,提示文件太大,无法上传.   解决方案: 找到 /usr/local/apache-tomcat7/webapps/manager/WEB- ...

  2. apache+mysql+php环境的手动搭建

    一.搭建Apache Http Server 官方下载地址:http://www.apachehaus.com/cgi-bin/download.plx 搭建环境:win10 64位 WIN10 64 ...

  3. 使用#define定义字面值和伪函数

    #define是C语言提供的宏命令,其主要目的是:在编程时,为程序员提供一定方便,并能在一定程度上提高程序的执行效率.#define将一个标示符定义为一个字符串,该标示符被称为宏,被定义的字符串称为字 ...

  4. 去掉xcode编译warning:ld: warning: directory not found for option '

    tyle="margin:20px 0px 0px; font-size:14px; line-height:26px; font-family:Arial; text-align:left ...

  5. 阅读 - Code Complete 2 - 第33章 - 个人性格

    个人性格对于软件项目的开发到底有没有作用或者影响呢? 有的人急于完成自己的工作,当自己的代码遇到问题的时候,不去自己思考并调试而是直接求助于他人,有的人则是自己沉住气,耐心的从头到尾的研究找到错误的所 ...

  6. node 上传文件 路径 重命名等问题

    最近在学习node,想做一个简单的网站.首先想到的是上传文件的功能,查了下,发现有一个formidable模块,操作方便,便拿来尝试了一下,结果很纠结. 下载安装的就不用说了,用npm即可.说一下,自 ...

  7. HDU 5818 Joint Stacks(左偏树)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5818 [题目大意] 给出两个栈A B(初始时为空),有三种操作: push.pop.merge. ...

  8. Android Develop【转】

    [Android Develop]   Android实现伸缩弹力分布菜单效果 摘要: 本文介绍下在Android中实现伸缩弹力分布菜单效果.关于这种菜单效果在IPhone中比较常见,效果比较酷.那么 ...

  9. iPhone开发之全局变量的使用

    全局变量历来就是很好的东西,能够在开发中带来很多方便,下面来介绍一下iPhone中软件开发时全局变量的使用方法: 一.新建Constants.h文件(文件名根据需要自己取),用于存放全局变量: 二.在 ...

  10. 有感PMI Exam Dev Workshop

    有幸參加了PMI协会在上海举办的PMI Exam Development Workshop活动.这是PMI协会第二次在中国举办此活动,上一次是2009年北京. 我第一次參加,感觉收获非常多. 我们知道 ...