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\n"); 14 printf("ev_async_send 调用前 %d\n",ev_async_pending(&async_watcher)); 15 ev_async_send(loop,&async_watcher);//这里会调用async_callback 16 printf("ev_async_send 调用后 %d\n",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\n"); 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\n"); 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\n"); 10 } 11 12 static void timeout_callback(struct ev_loop*loop,ev_timer *w,int revents) 13 { 14 printf("Time Out\n"); 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\n"); 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\n"); 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\n"); 18 } 19 20 static void timer_callback(struct ev_loop *loop,ev_timer *w,int revents) 21 { 22 printf("Call timer_callback\n"); 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\n"); 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\n"); 10 } 11 12 static void check_callback(struct ev_loop *loop,ev_check *w,int revents) 13 { 14 printf("Check Callback\n"); 15 } 16 17 static void timer_callback(struct ev_loop *loop,ev_timer *w,int revents) 18 { 19 printf("Timer Callback\n"); 20 } 21 22 static void sigint_callback(struct ev_loop *loop,ev_signal *w,int revents) 23 { 24 printf("Sigint Callback\n"); 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\n"); 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\n"); 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\n"); 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\n",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://www.cnblogs.com/wunaozai/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。 如果文中有什么错误,欢迎指出。以免更多的人被误导。有需要沟通的,可以站内私信,文章留言,或者关注“无脑仔的小明”公众号私信我。一定尽力回答。 |
【推荐】中国电信天翼云云端翼购节,2核2G云服务器一口价38元/年
【推荐】博客园携手 AI 驱动开发工具商 Chat2DB 推出联合终身会员
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在.NET Core中使用异步多线程高效率的处理大量数据
· 聊一聊 C#前台线程 如何阻塞程序退出
· 几种数据库优化技巧
· 聊一聊坑人的 C# MySql.Data SDK
· 使用 .NET Core 实现一个自定义日志记录器
· 字节豆包,来园广告
· 为什么推荐在 .NET 中使用 YAML 配置文件
· 订单超时自动取消,我们是这样做的。。。
· 在 .NET Core 中使用 Channel 实现生产者消费者模式
· C#字符串拼接的几种方式及其性能分析对比