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

  • 相关阅读:
    Java RunTime Environment (JRE) or Java Development Kit (JDK) must be available in order to run Eclipse. ......
    UVA 1597 Searching the Web
    UVA 1596 Bug Hunt
    UVA 230 Borrowers
    UVA 221 Urban Elevations
    UVA 814 The Letter Carrier's Rounds
    UVA 207 PGA Tour Prize Money
    UVA 1592 Database
    UVA 540 Team Queue
    UVA 12096 The SetStack Computer
  • 原文地址:https://www.cnblogs.com/wunaozai/p/3955156.html
Copyright © 2011-2022 走看看