##使用Libev Libev的做者写了一份很好的官方Manual,比较的齐全,即介绍了Libev的设计思想,也介绍了基本使用还包括内部各种事件详细介绍。这里略微赘述一下。Libev经过一个 ·struct ev_loop· 结结构表示一个事件驱动的框架。在这个框架里面经过ev_xxx
结构,ev_init
、ev_xxx_set
、ev_xxx_start
接口箱这个事件驱动的框架里面注册事件监控器,当相应的事件监控器的事件出现时,便会触发该事件监控器的处理逻辑,去处理该事件。处理完以后,这些监控器进入到下一轮的监控中。符合一个标准的事件驱动状态的模型。框架
Libev 除了提供了基本的三大类事件(IO事件、定时器事件、信号事件)外还提供了周期事件、子进程事件、文件状态改变事件等多个事件,这里咱们用三大基本事件写一个例子,和Manual上的相似,可是没有作收尾工做,为的是将事件的框架清晰的呈现出来。函数
#include<ev.h> #include <stdio.h> #include <signal.h> #include <sys/unistd.h> ev_io io_w; ev_timer timer_w; ev_signal signal_w; void io_action(struct ev_loop *main_loop,ev_io *io_w,int e) { int rst; char buf[1024] = {'\0'}; puts("in io cb\n"); read(STDIN_FILENO,buf,sizeof(buf)); buf[1023] = '\0'; printf("Read in a string %s \n",buf); ev_io_stop(main_loop,io_w); } void timer_action(struct ev_loop *main_loop,ev_timer *timer_w,int e) { puts("in tiemr cb \n"); ev_timer_stop(main_loop,timer_w); } void signal_action(struct ev_loop *main_loop,ev_signal signal_w,int e) { puts("in signal cb \n"); ev_signal_stop(main_loop,signal_w); ev_break(main_loop,EVBREAK_ALL); } int main(int argc ,char *argv[]) { struct ev_loop *main_loop = ev_default_loop(0); ev_init(&io_w,io_action); ev_io_set(&io_w,STDIN_FILENO,EV_READ); ev_init(&timer_w,timer_action); ev_timer_set(&timer_w,2,0); ev_init(&signal_w,signal_action); ev_signal_set(&signal_w,SIGINT); ev_io_start(main_loop,&io_w); ev_timer_start(main_loop,&timer_w); ev_signal_start(main_loop,&signal_w); ev_run(main_loop,0); return 0; }
下面对使用到的这些API进行说明。oop
这里使用了3种事件监控器,分别监控IO事件、定时器事件以及信号事件。所以定义了3个监控器(watcher),以及触发监控器时要执行动做的回调函数。Libev定义了多种监控器,命名方式为 ev_xxx
这里xxx表明监控器类型,其实现是一个结构体,设计
typedef struct ev_io { .... } ev_io;
经过宏定义能够简写为 ev_xxx
。回调函数的类型为 void cb_name(struct ev_loop *main_loop,ev_xxx *io_w,int event)
。code
在main中,首先定义了一个事件驱动器的结构 struct ev_loop *main_loop
这里调用 ev_default_loop(0)
生成一个预制的全局驱动器。这里能够参考Manual中的选择。而后依次初始化各个监控器以及设置监控器的触发条件。接口
初始化监控器的过程是将相应的回调函数即触发时的动做注册到监控器上。进程
设置触发条件则是该条件产生时才去执行注册到监控器上的动做。对于IO事件,通常是设置特定fd上的的可读或可写事件,定时器则是多久后触发。这里定时器的触发条件中还有第三参数,表示第一次触发后,是否循环,若为0则吧循环,不然按该值循环。信号触发器则是设置触发的信号。事件
在初始化并设置好触发条件后,先调用ev_xxx_start
将监控器注册到事件驱动器上。接着调用 ev_run
开始事件驱动器。get
在事件的触发动做里面。我加入了一个 ev_xxx_stop
函数,与上面对应,也就是讲改监控器从事件驱动器里面注销掉。使其再也不起做用。而在信号触发的动做中还加入了一个 ev_break
该函数可使进程跳出 main_loop
事件驱动器循环,也就是关闭事件驱动器。结束这一逻辑。回调函数
libev最简单的示例就是这样的一个结构。定义一个监控器、书写触发动做逻辑、初始化监控器、设置监控器触发条件、将监控器加入大事件驱动器的循环中便可。一个比较清晰的事件驱动框架。
libev的事件驱动过程能够想象成以下的伪代码:
do_some_init() is_run = True while is_run: t = caculate_loop_time() deal_loop(t) deal_with_pending_event() do_some_clear()
首先作一些初始化操做,而后进入到循环中,该循环经过一个状态位来控制是否执行。在循环中,计算出下一次轮询的时间,这里轮询的实现就采用了系统提供的epoll、kqueue等机制。再轮询结束后检查有哪些监控器的被触发了,依次执行触发动做。这里不要纠结信号事件、定时器时间咋都通过了 deal_loop
libev是如何实现的这里暂且不讨论,这个伪代码只是大体表示下libev的总体框架。