libev学习笔记

libev学习笔记

1.什么是libev?

libev是一个强大的网络reactor,支持多种事件(信号,I/O,定时器…..)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//基本数据类型的宏定义

# define EV_A loop
# define EV_A_ EV_A,
# define EV_P struct ev_loop *loop
# define EV_P_ EV_P,

typedef struct ev_io
{
EV_WATCHER_LIST (ev_io)
int fd; /* ro */
int events; /* ro */
} ev_io;

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
};

2.使用方法

1.创建ev_loop对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct ev_loop *ev_loop_new(unsigned int flag);
//创建一个ev_loop对象,这里的flag用于选择什么backend来实现多路复用
//flag的一些宏定义,一般用于选择后台多路复用机制,一般使用EVFLAG_AUTO(0)即可

* EVBACKEND_SELECT
* EVBACKEND_POLL
* EVBACKEND_EPOLL
* EVBACKEND_KQUEUE
* EVBACKEND_DEVPOLL
* EVBACKEND_PORT

* EVFLAG_NOINOTIFY // 不适用inofity调用来使用ev_stat.这样可以减少fd使用。
* EVFLAG_SIGNALFD // 使用signalfd来检测信号是否发生,同样这样可以减少fd

void ev_loop_destroy(EV_P);
//销毁一个ev_loop对象

2.绑定用户数据以及reactor的开始与退出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  void ev_set_userdata(EV_P_ void *data);
void *ev_userdata(EV_P);
//ev_loop如何运行和停止
void ev_run(EV_P_ int flags);
void ev_break(EV_P_ int how);
//flags参数
* 0 //通常这是我们想要的,每次轮询在poll都会等待一段时间然后处理pending事件。
* EVRUN_NOWAIT //运行一次,在poll时候不会等待。这样效果相当于只是处理pending事件。
* EVRUN_ONCE //运行一次,但是在poll时候会等待,然后处理pending事件。
而how有下面这几个:

* EVBREAK_ONE //只是退出一次ev_run这个调用。通常来说使用这个就可以了。
* EVBREAK_ALL //退出所有的ev_run调用。这种情况存在于ev_run在pengding处理时候会递归调
ev_set_loop_release_cb (EV_P_ void (*release)(EV_P) EV_NOEXCEPT, void (*acquire)(EV_P) EV_NOEXCEPT) //设置回调函数,用于epoll_wait前后调用

3.设置轮询时间

1
2
3
//在event_loop里面我们还关心一件事情,就是每次event_loop轮询的时间长短。通常来说这个不会是太大问题,但是在高性能情况下面我们需要设置
void ev_set_io_collect_interval(EV_P_ ev_tstamp interval);//设置轮询时间
void ev_set_timeout_collect_interval(EV_P_ ev_tstamp interval);//设置超时时间

4.Watcher

watcher 相当于eventhandler,一般ev_loop用于创建libev里面的reactor对象,而watcher就是事件触发后处理事件的模块,通常绑定fd,以及发生事件后处理事件的回调函数,下列的type用于区分不同的watcher
watcher的状态

  • initialiased 已经初始化

  • active 调用start进行注册

  • pending 已经触发事件但是还没有处理

  • inactive 调用stop注销.这个状态和已经初始化是一样的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    typedef void (*)(struct ev_loop *loop, ev_TYPE *watcher, int revents) callback; // callback都是这种类型
    ev_init (ev_TYPE *watcher, callback); // 初始化watcher
    ev_TYPE_set (ev_TYPE *watcher, [args]); // 设置watcher
    ev_TYPE_init (ev_TYPE *watcher, callback, [args]); // 通常使用这个函数最方便,初始化和设置都在这里
    ev_TYPE_start (loop, ev_TYPE *watcher); // 注册watcher
    ev_TYPE_stop (loop, ev_TYPE *watcher); // 注销watcher
    ev_set_priority (ev_TYPE *watcher, int priority); // 设置优先级
    ev_feed_event (loop, ev_TYPE *watcher, int revents); // 这个做跨线程通知非常有用,相当于触发了某个事件。

    bool ev_is_active (ev_TYPE *watcher); // watcher是否active.
    bool ev_is_pending (ev_TYPE *watcher); // watcher是否pending.
    int ev_clear_pending (loop, ev_TYPE *watcher); // 清除watcher pending状态并且返回事件

5.实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//一个简单的io驱动事件
#include <stdio.h>
#include <stdlib.h>
#include <ev.h>
void stdin_cb(EV_P_ ev_io *w,int revents)
{
puts("hello,world");
ev_io_stop(EV_A_ w);
ev_break(EV_A_ EVBREAK_ALL);
}
int main(int argc,char **argv)
{
struct ev_loop *loop= EV_DEFAULT;
ev_io stdin_watcher;
ev_io_init(&stdin_watcher,stdin_cb,0,EV_READ);//初始化watcher,设置事件处理的回调函数
ev_io_start(loop,&stdin_watcher);//设置reactor的watcher
ev_run(loop,0);//开始监听事件的到来,一旦事件到来,指向对应的watcher中的回调函数
return 0;
}

6.和epoll对比

ev_loop相当于struct event_base *base,监听集合
watcher相当于struct event *event,但是相比于epoll中的event,watcher中设置了相应的回调函数。
ev_run相当于epoll_wait函数开始监听事件的到来,到事件到来的时候调用相应的回调函数处理相应的事件


libev学习笔记
https://dreamaccount.github.io/2022/04/17/libev学习笔记/
作者
404NotFound
发布于
2022年4月17日
许可协议