这一小节继续讲解各个观察器(Watcher).

  上一小节已经讲解了ev_io(IO可读可写观察器),ev_stat(文件属性变化观察器),ev_signal(信号处理观察器),ev_timer(定时器),ev_periodic(周期任务处理),ev_child(子进程状态变化观察器)。这一小节准备讲ev_fork(创建的进程时的观察器),ev_async(异步调用观察器),ev_cleanup(event loop退出时触发事件),ev_prepare(每次event loop之前事件),ev_check(每次event loop之后事件),ev_idle(每次event loop空闲触发事件).

  ev_async  (ev_async当ev_async_send通过watcher调用时调用,触发EV_ASYNC)

 #include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <ev.h> ev_async async_watcher; static void sigint_callback(struct ev_loop *loop,ev_signal * w,int revents)
{
if(revents & EV_SIGNAL)
{
printf("Call sigint_callback\n");
printf("ev_async_send 调用前 %d\n",ev_async_pending(&async_watcher));
ev_async_send(loop,&async_watcher);//这里会调用async_callback
printf("ev_async_send 调用后 %d\n",ev_async_pending(&async_watcher));
}
} static void sigquit_callback(struct ev_loop *loop,ev_signal *w,int revetns)
{
printf("Call sigquit_callback\n");
ev_break(loop,EVBREAK_ALL);
} static void async_callback(struct ev_loop *loop,ev_async *w,int revents)
{
if(revents & EV_ASYNC)
{
printf("Call async_callback\n");
}
} int main(int argc, char **args)
{
struct ev_loop *main_loop=ev_default_loop(); ev_init(&async_watcher,async_callback);
ev_async_start(main_loop,&async_watcher); ev_signal sigint_watcher;
ev_init(&sigint_watcher,sigint_callback);
ev_signal_set(&sigint_watcher,SIGINT);
ev_signal_start(main_loop,&sigint_watcher); ev_signal sigquit_watcher;//这里的ev_signal不能与上面共用,必须在声明一个变量
ev_init(&sigquit_watcher,sigquit_callback);
ev_signal_set(&sigquit_watcher,SIGQUIT);
ev_signal_start(main_loop,&sigquit_watcher); ev_run(main_loop,);
return ;
}

  下面这个是运行截图

  可以看出程序ev_async这个是通过ev_async_send来驱动async_callback这个回调函数执行的。而且ev_async_pending这个也是可以判断ev_async是否处于pending状态。我在第15行处增加了sleep(1)后,运行的结构还是一样,可以看出ev_async所绑定的回调函数是处于pending状态而不是另外开一个线程(进程)来执行的。

  从上面的处理机制看,好像就是发送一个信号,然后ev_async就调用回调函数去执行,好像跟ev_signal一样,没有什么特点啊。这里给出官方文档的解释。

This functionality is very similar to ev_signal watchers, as signals, too, are asynchronous in nature, and signals, too, will be compressed (i.e. the number of callback invocations may be less than the number of ev_async_sent calls).

Unlike ev_signal watchers, ev_async works with any event loop, not just the default loop.

  上面说到,不同与ev_signal watchers的是,ev_async可以在多种event loop,而不是默认的loop。前几小节已经讲到ev_loop 的创建,可以通过ev_loop_new进行创建(创建异步事件什么的)。具体的用法这里还不是很清楚,先跳过。

  ev_fork (开辟进程时观察器)

 #include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <ev.h> static void fork_callback(struct ev_loop *loop,ev_fork *w,int revents)
{
printf("Call fork_callback\n");
} static void timeout_callback(struct ev_loop*loop,ev_timer *w,int revents)
{
printf("Time Out\n");
ev_break(loop,EVBREAK_ALL);
} int main(int argc, char **args)
{
struct ev_loop *main_loop=ev_default_loop(); ev_fork fork_watcher;
ev_init(&fork_watcher,fork_callback);
ev_fork_start(main_loop,&fork_watcher); ev_timer timer_watcher;
ev_init(&timer_watcher,timeout_callback);
ev_timer_set(&timer_watcher,,);
ev_timer_start(main_loop,&timer_watcher); switch(fork())
{
case -:
break;
case ://child
//ev_loop_fork(main_loop);
break;
} ev_run(main_loop,);
return ;
}

  上面这个代码没有输出Call fork_callback,如果把第36行的注释去掉,就会输出Call fork_callback了,可以说明这个ev_fork不是针对fork函数创建的进程。而是要ev_loop_fork针对ev_loop 创建的loop。具体解释的不是很清楚,下面给出官方文档:

Fork watchers are called when a fork () was detected (usually because whoever is a good citizen cared to tell libev about it by calling ev_default_fork or ev_loop_fork). The invocation is done before the event loop blocks next and before ev_check watchers are being called, and only in the child after the fork. If whoever good citizen calling ev_default_fork cheats and calls it in the wrong process, the fork handlers will be invoked, too, of course.

  loop的创建小解

 struct ev_loop *ev_default_loop (unsigned int flags) 
struct ev_loop *ev_loop_new (unsigned int flags) 
//这两个函数都是默认原始化一个loop,区别是第一个不是线程安全的,第二个不能捕捉信号和子进程的watcher。
//参数flags可以为下面几种类型:
//引用
#define EVFLAG_AUTO 0x00000000U /* not quite a mask */
/* flag bits */
#define EVFLAG_NOENV 0x01000000U /* do NOT consult environment */
#define EVFLAG_FORKCHECK 0x02000000U /* check for a fork in each iteration */
/* method bits to be ored together */
#define EVBACKEND_SELECT 0x00000001U /* about anywhere */
#define EVBACKEND_POLL 0x00000002U /* !win */
#define EVBACKEND_EPOLL 0x00000004U /* linux */
#define EVBACKEND_KQUEUE 0x00000008U /* bsd */
#define EVBACKEND_DEVPOLL 0x00000010U /* solaris 8 */ /* NYI */
#define EVBACKEND_PORT 0x00000020U /* solaris 10 */
ev_default_fork () 
ev_loop_fork (loop)
//这两个函数就是当你在子进程里须要 运用 libev的函数的之前必须要调用。他们的区别是第二个函数是当运用 ev_loop_new建立 的loop时,才用第二个函数,也就是说重用父进程建立 的loop。
ev_loop (loop, int flags)
//开始事件循环。
ev_TYPE_init (ev_TYPE *watcher, callback, [args])
//原始化一个watcher。TYPE也就是libev支持的事件类型,比如io,比如time等等。。
//第一个参数为一个watcher,第二个回调函数,第三个句柄,第四个事件类型。包含下面几种:
//引用
#define EV_UNDEF -1 /* guaranteed to be invalid */
#define EV_NONE 0x00 /* no events */
#define EV_READ 0x01 /* ev_io detected read will not block */
#define EV_WRITE 0x02 /* ev_io detected write will not block */
#define EV_IOFDSET 0x80 /* internal use only */
#define EV_TIMEOUT 0x00000100 /* timer timed out */
#define EV_PERIODIC 0x00000200 /* periodic timer timed out */
#define EV_SIGNAL 0x00000400 /* signal was received */
#define EV_CHILD 0x00000800 /* child/pid had status change */
#define EV_STAT 0x00001000 /* stat data changed */
#define EV_IDLE 0x00002000 /* event loop is idling */
#define EV_PREPARE 0x00004000 /* event loop about to poll */
#define EV_CHECK 0x00008000 /* event loop finished poll */
#define EV_EMBED 0x00010000 /* embedded event loop needs sweep */
#define EV_FORK 0x00020000 /* event loop resumed in child */
#define EV_ASYNC 0x00040000 /* async intra-loop signal */
#define EV_ERROR 0x80000000 /* sent when an error occurs */
//引用
ev_TYPE_start (loop *, ev_TYPE *watcher)
//启动一个watcher。
     switch(fork())
{
case -:
break;
case ://child
ev_loop_fork(main_loop);//使用父进程main_loop
ev_timer timer_watcher1;
ev_init(&timer_watcher1,timeout_callback);
ev_timer_set(&timer_watcher1,,);
ev_timer_start(main_loop,&timer_watcher1);
break;
}

  上面代码如果修改如下是可以编译通过的。就是在父进程中的main_loop中再增加一个watcher,这个程序将会输出三次Time Out。注意如果没有第六行的ev_loop_fork是编译不通过的。大概的原因是ev库设计的原因。

  下面给出一个例子,用于以后可以参考用

 #include <ev.h>
#include <stdio.h> //不同的watcher
ev_io stdin_watcher;
ev_timer timeout_watcher;
ev_timer timeout_watcher_child; //标准输入的回调函数
static void stdin_cb (EV_P_ ev_io *w, int revents)
{
puts ("stdin ready");
ev_io_stop (EV_A_ w);
ev_unloop (EV_A_ EVUNLOOP_ALL);
} //父进程的定时器回调函数
static void timeout_cb (EV_P_ ev_timer *w, int revents)
{
puts ("timeout");
ev_unloop (EV_A_ EVUNLOOP_ONE);
}
//子进程的定时器回调函数
static void timeout_cb_child (EV_P_ ev_timer *w, int revents)
{
puts ("child timeout");
ev_unloop (EV_A_ EVUNLOOP_ONE);
} static void fork_callback(struct ev_loop *loop,ev_fork *w,int revents)
{
printf("Call fork_callback\n");
} int main (void)
{
//创建一个backend为select的loop
struct ev_loop *loop = ev_loop_new(EVBACKEND_SELECT); //初始化并启动父进程的watcher
ev_timer_init(&timeout_watcher, timeout_cb, , .);
ev_timer_start(loop, &timeout_watcher);
switch (fork()) {
case -:
return -;
case :
//使用父进程loop。
ev_loop_fork(loop);
//子进程的loop
struct ev_loop *loop_child = ev_loop_new (EVBACKEND_SELECT);
ev_io_init (&stdin_watcher, stdin_cb, /*STDIN_FILENO*/ , EV_READ);
ev_io_start (loop, &stdin_watcher);
ev_timer_init(&timeout_watcher_child, timeout_cb_child, 5.5, .);
ev_timer_start(loop_child, &timeout_watcher_child);
ev_loop(loop_child,);
} //等待事件
ev_loop (loop, );
return ;
}

  ev_cleanup  event loop 退出触发事件

 #include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <ev.h> struct ev_loop *main_loop; static void program_exits(void)
{
printf("Call AtExit\n");
ev_loop_destroy(EV_DEFAULT);//注释掉43行处代码,该函数在这里没有调用到cleanup_callback,但是却执行没有错误
} static void cleanup_callback(struct ev_loop *loop,ev_cleanup *w,int revents)
{
printf("Call cleanup_callback\n");
} static void timer_callback(struct ev_loop *loop,ev_timer *w,int revents)
{
printf("Call timer_callback\n");
} int main(int argc, char **args)
{
//struct ev_loop *main_loop=ev_default_loop(0);//error 注意ev_loop_destroy与ev_loop_new对应
main_loop=ev_loop_new(EVBACKEND_EPOLL); ev_cleanup cleanup_watcher;
ev_init(&cleanup_watcher,cleanup_callback);
ev_cleanup_start(main_loop,&cleanup_watcher); ev_timer timer_watcher;
ev_init(&timer_watcher,timer_callback);
ev_timer_set(&timer_watcher,0.2,);
ev_timer_start(main_loop,&timer_watcher); atexit(program_exits); ev_run(main_loop,); ev_loop_destroy(main_loop);//在这里就可以调用到cleanup_callback
printf("END\n");
return ;
}

  运行时截图

  ev_prepare  (每次event loop之前事件)

  ev_check  (每次event loop之后事件)

 #include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <ev.h> static void prepare_callback(struct ev_loop *loop,ev_prepare *w,int revents)
{
printf("Prepare Callback\n");
} static void check_callback(struct ev_loop *loop,ev_check *w,int revents)
{
printf("Check Callback\n");
} static void timer_callback(struct ev_loop *loop,ev_timer *w,int revents)
{
printf("Timer Callback\n");
} static void sigint_callback(struct ev_loop *loop,ev_signal *w,int revents)
{
printf("Sigint Callback\n");
ev_break(loop,EVBREAK_ALL);
} int main(int argc, char **args)
{
struct ev_loop *main_loop=ev_default_loop(); ev_prepare prepare_watcher;
ev_check check_watcher;
ev_timer timer_watcher;
ev_signal signal_watcher; ev_prepare_init(&prepare_watcher,prepare_callback);
ev_check_init(&check_watcher,check_callback);
ev_timer_init(&timer_watcher,timer_callback,,);
ev_signal_init(&signal_watcher,sigint_callback,SIGINT); ev_prepare_start(main_loop,&prepare_watcher);
ev_check_start(main_loop,&check_watcher);
ev_timer_start(main_loop,&timer_watcher);
ev_signal_start(main_loop,&signal_watcher); ev_run(main_loop,);
return ;
}

  运行结果

  看前三个为一组,我测试了几次都是这样,Timer Callback的输出都是在Check之后,这个不知道为什么不过后面的捕获SIGINT信号就没有这个问题,SIGINT信号的回调函数的输出是处于Prepare和Check之间。这个就符合预想。还有就是我们输入一个Ctrl-C时,也会触发Prepare-Check的回调函数。这个倒是没有想到,应该是一个ev_signal会向ev_loop里放入两个处理过程,一个是Linux默认的捕获SIGINT信号(signal函数)一个是我们的回调函数,大概是在默认的回调函数中调用我们的回调函数,毕竟捕获信号是系统调用。上面这个是我的猜想(理解),不一定是正确的。

  ev_idle (每次event loop空闲触发事件)

 #include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <ev.h> ev_idle idle_watcher;
int count=; static void timer_callback_start(struct ev_loop *loop,ev_timer *w,int revents)
{
printf("Timer Callback Start\n");
ev_idle_start(loop,&idle_watcher);
}
static void timer_callback_stop(struct ev_loop *loop,ev_timer *w,int revents)
{
printf("Timer Callback Stop\n");
ev_idle_stop(loop,&idle_watcher);
} static void sigint_callback(struct ev_loop *loop,ev_signal *w,int revents)
{
printf("Sigint Callback\n");
ev_break(loop,EVBREAK_ALL);
} static void idle_callback(struct ev_loop *loop,ev_idle *w,int revents)
{
count++;
} int main(int argc, char **args)
{
struct ev_loop *main_loop=ev_default_loop(); ev_timer timer_watcher_start;
ev_timer timer_watcher_stop;
ev_signal signal_watcher; ev_idle_init(&idle_watcher,idle_callback);
ev_timer_init(&timer_watcher_start,timer_callback_start,,);
ev_timer_init(&timer_watcher_stop,timer_callback_stop,,);
ev_signal_init(&signal_watcher,sigint_callback,SIGINT); ev_timer_start(main_loop,&timer_watcher_start);
ev_timer_start(main_loop,&timer_watcher_stop);
ev_signal_start(main_loop,&signal_watcher); ev_run(main_loop,); printf("从第1秒到第3秒之间count计数器的累加到 %d\n",count);
return ;
}

  运行结果

  我们的idle是可以控制开始和结束的。而这个idle的作用是但event_loop处于空闲的时候,与其在ev_run阻塞等待,不如利用这时的cpu时间来做其他事。应用的话,就是如果服务器繁忙的话就主要处理请求等,如果服务器请求不多时,可以利用cpu时间来处理备份什么的,这样就可以最大限度的利用cpu了。

  观察器watcher差不多就这些了,还有个ev_embed这个还不会用。

  参考资料: http://wangjunle23.blog.163.com/blog/static/11783817120124308920321/

        : http://simohayha.iteye.com/blog/306712

  本文地址: http://www.cnblogs.com/wunaozai/p/3955156.html

Socket网络编程--Libev库学习(3)的更多相关文章

  1. Socket网络编程--Libev库学习(1)

    这一节是安装篇. Socket网络编程不知不觉已经学了快两个月了.现在是时候找个网络库学学了.搜索了很多关于如何学网络编程的博客和问答.大致都是推荐学一个网络库,至于C++网络库有那么几个,各有各的好 ...

  2. Socket网络编程--Libev库学习(2)

    这一小节讲各个观察器(Watcher) 在libev下面watcher相当于EventHandler这么一个概念,通常里面会绑定fd回调函数以及我们需要关注的事件. 然后一旦触发事件之后会触发我们使用 ...

  3. python之Socket网络编程

    什么是网络? 网络是由节点和连线构成,表示诸多对象及其相互联系.在数学上,网络是一种图,一般认为专指加权图.网络除了数学定义外,还有具体的物理含义,即网络是从某种相同类型的实际问题中抽象出来的模型.在 ...

  4. windows socket 网络编程

    样例代码就在我的博客中,包含六个UDP和TCP发送接受的cpp文件,一个基于MFC的局域网聊天小工具project,和此小工具的全部执行时库.资源和执行程序.代码的压缩包位置是http://www.b ...

  5. Linux Socket 网络编程

    Linux下的网络编程指的是socket套接字编程,入门比较简单.在学校里学过一些皮毛,平时就是自学玩,没有见识过真正的socket编程大程序,比较遗憾.总感觉每次看的时候都有收获,但是每次看完了之后 ...

  6. Python Socket 网络编程

    Socket 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的,例如我们每天浏览网页.QQ ...

  7. Python全栈【Socket网络编程】

    Python全栈[socket网络编程] 本章内容: Socket 基于TCP的套接字 基于UDP的套接字 TCP粘包 SocketServer 模块(ThreadingTCPServer源码剖析) ...

  8. Python之路【第七篇】python基础 之socket网络编程

    本篇文章大部分借鉴 http://www.cnblogs.com/nulige/p/6235531.html python socket  网络编程 一.服务端和客户端 BS架构 (腾讯通软件:ser ...

  9. Socket网络编程--FTP客户端

    Socket网络编程--FTP客户端(1)(Windows) 已经好久没有写过博客进行分享了.具体原因,在以后说. 这几天在了解FTP协议,准备任务是写一个FTP客户端程序.直接上干货了. 0.了解F ...

随机推荐

  1. 设置char变量指定位为0或1

    int GetBit(char c,int i)//取c的第i位 { ; } void SetBit(char & c,int i, int v)//设置c的第i位为v,v是0或1 { if( ...

  2. BackgroundWorker使用方法

    在做GUI界面程序的时候,经常会遇到执行长时间方法的需求,当执行长时间方法的同时,再去点击界面,界面就会出现“卡死.假死”的现象,这是因为界面GUI线程被阻塞而导致暂时无响应.解决的方法有很多种,下面 ...

  3. sort.js

    JavaScript to achieve the ten common sorting algorithm library 1 ; (function (global, factory) { // ...

  4. android中的目录结构介绍

      Google Android手机的软件为了安全性和稳定性都是默认安装到手机内存里,但是手机内存有限,所以我们会做app2sd操作,来让我们安装的软件放到sd卡上,这个操作是需要rom的支持的.   ...

  5. Axure快速原型教程02--创建页面和设置界面

    目录 Axure快速原型教程02--创建页面和设置界面 Axure快速原型教程01--原型说明下载和安装 首先,在左侧的面板中,我们发现有一个叫sitemap的面板,这个面板就是我们的一个个的页面了, ...

  6. 阿里云ECS 利用快照创建磁盘实现无损扩容数据盘

    在扩容数据盘时,若遇到磁盘原因导致无法无损的扩容时,可以临时购买一块独立云磁盘来存放数据,然后将数据盘彻底格式化来解决,以下是操作步骤: 1.  首先基于当前数据盘创建一个快照,备份数据,同时可以利用 ...

  7. ubuntu 终端中文显示乱码问题!

    1 Alt+Ctrl+F1 进入第一个终端,发现中文乱码. 2 安装zhcon. sudo apt-get install zhcon 3 输入下面命令,启动zhcon,中文显示正常. zhcon - ...

  8. Swift中的Any 与 AnyObject、AnyClass的区别?

    在 Swift 中能够表示 “任意” 这个概念的除了Any .AnyObject以外,还有一个AnyClass. Any.AnyObject.AnyClass有什么区别: AnyObject是一个成员 ...

  9. tf.gfile

    一.功能和目的 tf.gfile模块定义在tensorflow/python/platform/gfile.py,但其源代码实现主要位于tensorflow/tensorflow/python/lib ...

  10. Seqlite学习

    之前没有接触过数据库编程,尼玛,面试神码的最恶心了,非得神码都懂点,好吧,最近开始研究下,先从SQLite开始吧,贴上找到SQliteDB.之后搜集资料,慢慢学习!