zoukankan      html  css  js  c++  java
  • Socket网络编程--Libev库学习(3)

      这一小节继续讲解各个观察器(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)

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <unistd.h>
     4 #include <stdlib.h>
     5 #include <ev.h>
     6 
     7 ev_async async_watcher;
     8 
     9 static void sigint_callback(struct ev_loop *loop,ev_signal * w,int revents)
    10 {
    11     if(revents & EV_SIGNAL)
    12     {
    13         printf("Call sigint_callback
    ");
    14         printf("ev_async_send 调用前 %d
    ",ev_async_pending(&async_watcher));
    15         ev_async_send(loop,&async_watcher);//这里会调用async_callback
    16         printf("ev_async_send 调用后 %d
    ",ev_async_pending(&async_watcher));
    17     }
    18 }
    19 
    20 static void sigquit_callback(struct ev_loop *loop,ev_signal *w,int revetns)
    21 {
    22     printf("Call sigquit_callback
    ");
    23     ev_break(loop,EVBREAK_ALL);
    24 }
    25 
    26 static void async_callback(struct ev_loop *loop,ev_async *w,int revents)
    27 {
    28     if(revents & EV_ASYNC)
    29     {
    30         printf("Call async_callback
    ");
    31     }
    32 }
    33 
    34 int main(int argc, char **args)
    35 {
    36     struct ev_loop *main_loop=ev_default_loop(0);
    37 
    38     ev_init(&async_watcher,async_callback);
    39     ev_async_start(main_loop,&async_watcher);
    40 
    41     ev_signal sigint_watcher;
    42     ev_init(&sigint_watcher,sigint_callback);
    43     ev_signal_set(&sigint_watcher,SIGINT);
    44     ev_signal_start(main_loop,&sigint_watcher);
    45 
    46     ev_signal sigquit_watcher;//这里的ev_signal不能与上面共用,必须在声明一个变量
    47     ev_init(&sigquit_watcher,sigquit_callback);
    48     ev_signal_set(&sigquit_watcher,SIGQUIT);
    49     ev_signal_start(main_loop,&sigquit_watcher);
    50 
    51     ev_run(main_loop,0);
    52     return 0;
    53 }

      下面这个是运行截图

      可以看出程序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 (开辟进程时观察器)

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <unistd.h>
     4 #include <stdlib.h>
     5 #include <ev.h>
     6 
     7 static void fork_callback(struct ev_loop *loop,ev_fork *w,int revents)
     8 {
     9     printf("Call fork_callback
    ");
    10 }
    11 
    12 static void timeout_callback(struct ev_loop*loop,ev_timer *w,int revents)
    13 {
    14     printf("Time Out
    ");
    15     ev_break(loop,EVBREAK_ALL);
    16 }
    17 
    18 int main(int argc, char **args)
    19 {
    20     struct ev_loop *main_loop=ev_default_loop(0);
    21 
    22     ev_fork fork_watcher;
    23     ev_init(&fork_watcher,fork_callback);
    24     ev_fork_start(main_loop,&fork_watcher);
    25 
    26     ev_timer timer_watcher;
    27     ev_init(&timer_watcher,timeout_callback);
    28     ev_timer_set(&timer_watcher,3,0);
    29     ev_timer_start(main_loop,&timer_watcher);
    30 
    31     switch(fork())
    32     {
    33         case -1:
    34             break;
    35         case 0://child
    36             //ev_loop_fork(main_loop);
    37             break;
    38     }
    39 
    40     ev_run(main_loop,0);
    41     return 0;
    42 }

      上面这个代码没有输出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的创建小解

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

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

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

     1 #include <ev.h>
     2 #include <stdio.h>
     3 
     4 //不同的watcher
     5 ev_io stdin_watcher;
     6 ev_timer timeout_watcher;
     7 ev_timer timeout_watcher_child;
     8 
     9 //标准输入的回调函数
    10 static void stdin_cb (EV_P_ ev_io *w, int revents)
    11 {
    12     puts ("stdin ready");
    13     ev_io_stop (EV_A_ w);
    14     ev_unloop (EV_A_ EVUNLOOP_ALL);
    15 }
    16 
    17 //父进程的定时器回调函数
    18 static void timeout_cb (EV_P_ ev_timer *w, int revents)
    19 {
    20     puts ("timeout");
    21     ev_unloop (EV_A_ EVUNLOOP_ONE);
    22 }
    23 //子进程的定时器回调函数
    24 static void timeout_cb_child (EV_P_ ev_timer *w, int revents)
    25 {
    26     puts ("child timeout");
    27     ev_unloop (EV_A_ EVUNLOOP_ONE);
    28 }
    29 
    30 static void fork_callback(struct ev_loop *loop,ev_fork *w,int revents)
    31 {
    32     printf("Call fork_callback
    ");
    33 }
    34 
    35 int main (void)
    36 {
    37     //创建一个backend为select的loop
    38     struct ev_loop *loop = ev_loop_new(EVBACKEND_SELECT);
    39 
    40     //初始化并启动父进程的watcher
    41     ev_timer_init(&timeout_watcher, timeout_cb, 10, 0.);
    42     ev_timer_start(loop, &timeout_watcher);
    43     switch (fork()) {
    44         case -1:
    45             return -1;
    46         case 0:
    47             //使用父进程loop。
    48             ev_loop_fork(loop);
    49             //子进程的loop
    50             struct ev_loop *loop_child = ev_loop_new (EVBACKEND_SELECT);
    51             ev_io_init (&stdin_watcher, stdin_cb, /*STDIN_FILENO*/ 0, EV_READ);
    52             ev_io_start (loop, &stdin_watcher);
    53             ev_timer_init(&timeout_watcher_child, timeout_cb_child, 5.5, 0.);
    54             ev_timer_start(loop_child, &timeout_watcher_child);
    55             ev_loop(loop_child,0);
    56     }
    57 
    58     //等待事件
    59     ev_loop (loop, 0);
    60     return 0;
    61 }

      ev_cleanup  event loop 退出触发事件

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <unistd.h>
     4 #include <stdlib.h>
     5 #include <ev.h>
     6 
     7 struct ev_loop *main_loop;
     8 
     9 static void program_exits(void)
    10 {
    11     printf("Call AtExit
    ");
    12     ev_loop_destroy(EV_DEFAULT);//注释掉43行处代码,该函数在这里没有调用到cleanup_callback,但是却执行没有错误
    13 }
    14 
    15 static void cleanup_callback(struct ev_loop *loop,ev_cleanup *w,int revents)
    16 {
    17     printf("Call cleanup_callback
    ");
    18 }
    19 
    20 static void timer_callback(struct ev_loop *loop,ev_timer *w,int revents)
    21 {
    22     printf("Call timer_callback
    ");
    23 }
    24 
    25 int main(int argc, char **args)
    26 {
    27     //struct ev_loop *main_loop=ev_default_loop(0);//error 注意ev_loop_destroy与ev_loop_new对应
    28     main_loop=ev_loop_new(EVBACKEND_EPOLL);
    29 
    30     ev_cleanup cleanup_watcher;
    31     ev_init(&cleanup_watcher,cleanup_callback);
    32     ev_cleanup_start(main_loop,&cleanup_watcher);
    33 
    34     ev_timer timer_watcher;
    35     ev_init(&timer_watcher,timer_callback);
    36     ev_timer_set(&timer_watcher,0.2,0);
    37     ev_timer_start(main_loop,&timer_watcher);
    38 
    39     atexit(program_exits);
    40 
    41     ev_run(main_loop,0);
    42 
    43     ev_loop_destroy(main_loop);//在这里就可以调用到cleanup_callback
    44     printf("END
    ");
    45     return 0;
    46 }

      运行时截图

      ev_prepare  (每次event loop之前事件)

      ev_check  (每次event loop之后事件)

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <unistd.h>
     4 #include <stdlib.h>
     5 #include <ev.h>
     6 
     7 static void prepare_callback(struct ev_loop *loop,ev_prepare *w,int revents)
     8 {
     9     printf("Prepare Callback
    ");
    10 }
    11 
    12 static void check_callback(struct ev_loop *loop,ev_check *w,int revents)
    13 {
    14     printf("Check Callback
    ");
    15 }
    16 
    17 static void timer_callback(struct ev_loop *loop,ev_timer *w,int revents)
    18 {
    19     printf("Timer Callback
    ");
    20 }
    21 
    22 static void sigint_callback(struct ev_loop *loop,ev_signal *w,int revents)
    23 {
    24     printf("Sigint Callback
    ");
    25     ev_break(loop,EVBREAK_ALL);
    26 }
    27 
    28 int main(int argc, char **args)
    29 {
    30     struct ev_loop *main_loop=ev_default_loop(0);
    31 
    32     ev_prepare prepare_watcher;
    33     ev_check check_watcher;
    34     ev_timer timer_watcher;
    35     ev_signal signal_watcher;
    36 
    37     ev_prepare_init(&prepare_watcher,prepare_callback);
    38     ev_check_init(&check_watcher,check_callback);
    39     ev_timer_init(&timer_watcher,timer_callback,2,0);
    40     ev_signal_init(&signal_watcher,sigint_callback,SIGINT);
    41 
    42     ev_prepare_start(main_loop,&prepare_watcher);
    43     ev_check_start(main_loop,&check_watcher);
    44     ev_timer_start(main_loop,&timer_watcher);
    45     ev_signal_start(main_loop,&signal_watcher);
    46 
    47     ev_run(main_loop,0);
    48     return 0;
    49 }

      运行结果

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

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

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <unistd.h>
     4 #include <stdlib.h>
     5 #include <ev.h>
     6 
     7 ev_idle idle_watcher;
     8 int count=0;
     9 
    10 static void timer_callback_start(struct ev_loop *loop,ev_timer *w,int revents)
    11 {
    12     printf("Timer Callback Start
    ");
    13     ev_idle_start(loop,&idle_watcher);
    14 }
    15 static void timer_callback_stop(struct ev_loop *loop,ev_timer *w,int revents)
    16 {
    17     printf("Timer Callback Stop
    ");
    18     ev_idle_stop(loop,&idle_watcher);
    19 }
    20 
    21 static void sigint_callback(struct ev_loop *loop,ev_signal *w,int revents)
    22 {
    23     printf("Sigint Callback
    ");
    24     ev_break(loop,EVBREAK_ALL);
    25 }
    26 
    27 static void idle_callback(struct ev_loop *loop,ev_idle *w,int revents)
    28 {
    29     count++;
    30 }
    31 
    32 int main(int argc, char **args)
    33 {
    34     struct ev_loop *main_loop=ev_default_loop(0);
    35 
    36     ev_timer timer_watcher_start;
    37     ev_timer timer_watcher_stop;
    38     ev_signal signal_watcher;
    39 
    40     ev_idle_init(&idle_watcher,idle_callback);
    41     ev_timer_init(&timer_watcher_start,timer_callback_start,1,0);
    42     ev_timer_init(&timer_watcher_stop,timer_callback_stop,3,0);
    43     ev_signal_init(&signal_watcher,sigint_callback,SIGINT);
    44 
    45     ev_timer_start(main_loop,&timer_watcher_start);
    46     ev_timer_start(main_loop,&timer_watcher_stop);
    47     ev_signal_start(main_loop,&signal_watcher);
    48 
    49     ev_run(main_loop,0);
    50 
    51     printf("从第1秒到第3秒之间count计数器的累加到 %d
    ",count);
    52     return 0;
    53 }

      运行结果

      我们的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

  • 相关阅读:
    RedHat Linux AS 5下memcached的安装
    System.Diagnostics.Debug和System.Diagnostics.Trace
    设置c#windows服务描述及允许服务与桌面交互的几种方法
    在WinForm中使用WebServices来实现软件自动升级(AutoUpdate)(C#)
    从客户端中检测到有潜在危险的 Request.Form 值
    discuz数据库迁移,改密码后,相关配置文件修改
    C#取得页面执行时间的代码
    RedHat 解决 ifconfig命令不能使用的问题
    System.ServiceProcess 命名空间下10个类的列表
    Excel导入,导出,模板生成公共模块整理
  • 原文地址:https://www.cnblogs.com/wunaozai/p/3955156.html
Copyright © 2011-2022 走看看