关于Eventloop的概念

最近了解了一下 eventloop 这个概念,所以想写一篇文章整理一下思路。
1、eventloop 是什么?
我在网上看了一些资料,但都比较复杂,而且大多和 javascript 扯上关系,对初学者不友好。
我个人理解的 eventloop,其实就是在一个大循环里,处理各种各样的事件。只是不同的 eventloop 机制或者库,在性能和适用场景之间有差别罢了。
一个程序,只要它需要一直工作,就会处于一个持续循环运行的状态,我把这个循环的状态,称为 eventloop。
举个简单的例子:
int main(){    int choice;    do {        // 等待用户输入     choice = getch();        switch (choice) {        case 'q':            break;        case 'a':            add_record();            break;        [...]        }    } while (choice != 'q');    exit(exit_success);}  
上面这个程序,在一个 while 循环里,根据不同的键盘输入事件,而执行不同的操作。
这就是一个简单的 eventloop,只是这个 eventloop 只处理一种事件:键盘输入,且是阻塞等待,虽然很简陋,但是对于上面这个场景而言,已经够用了。
eventloop 随处可见:
许多开源软件,只要它们有持续运行 + 事件处理的需求,就会有自己的 eventloop 实现,例如:
图形库 qt 里的 qguiapplication::run();
多媒体库 sdl2 里的 sdl_pollevent();
网络库 mongoose 里的 mg_mgr_poll();
本质上都是一种 eventloop,只是由于需求和应用场景的不一样,各自的实现方法有所差异。
合格的 eventloop:
一个合格的 eventloop,需要有哪些特性?
我个人认为:
1、不要阻塞,即不要调用可能会阻塞的系统调用,或总是以 nonblocking 的方式调用系统调用。
2、能异步处理事件。
3、性能尽量高,以满足业务需求为下限。
满足上述三点,这个 eventloop 在功能上就是够用的。
2、eventloop 怎么用?
基于 select 的 eventloop:
这是来自 unix 网络编程 16.2 章节的一个例子,其大致代码如下:
str_cli(file *fp, int sockfd){    ...    // set nonblock    val = fcntl(sockfd, f_getfl, 0); fcntl(sockfd, f_setfl, val | o_nonblock);    // eventloop    for ( ; ; ) {        ...        select(maxfdp1, &rset, &wset, null, null);        if (fd_isset(sockfd, &rset)) {            // do something        }        ... // other event    }}  
这个程序会从标准输入中读取一行数据,然后通过 socket 发送给服务端,然后接收服务端的响应,最后将响应也写到标准输出。
最关键的点是先调用 fcntl 将所有的输入输出都设置为 nonblock,然后用 select 监测所有的文件描述符。
基本上所有的开源事件库,本质上和这个程序没差别。
各种开源的 eventloop 库:
由于 eventloop 是一个比较通用的需求,在开源软件里,有许多优秀的异步事件库都实现了这个功能。
比较适合嵌入式领域异步事件库有 3 个:
libevent:an event notification library.
名气最大,应用最广泛,历史最悠久的跨平台事件库。
libev:a high performance full-featured event loop written in c.
较 libevent 而言,设计更简练,但是对 windows 支持不够好,并且和开源社区不怎么接轨。
libuv:a multi-platform support library with a focus on asynchronous i/o.
点击查看大图
开发 node.js 的过程中需要一个跨平台的事件库,目前非常活跃,推荐大家重点学习。
libev 最精简,入门最容易,这里用它来介绍一下事件库的用法:
#include #include  // 定义两个事件 watcherev_io stdin_watcher;ev_timer timeout_watcher;// io watcher 的回调函数static voidstdin_cb (ev_p_ ev_io *w, int revents){  puts (stdin ready);  ev_io_stop (ev_a_ w);   ev_break (ev_a_ evbreak_all);}// timer watcher 的回调函数static voidtimeout_cb (ev_p_ ev_timer *w, int revents){  puts (timeout);  ev_break (ev_a_ evbreak_one);} int main (void){  // 定义 eventloop  struct ev_loop *loop = ev_default;  // 初始化 io watcher   ev_io_init (&stdin_watcher, stdin_cb, /*stdin_fileno*/ 0, ev_read);  ev_io_start (loop, &stdin_watcher);  // 初始化 timer watcher   ev_timer_init (&timeout_watcher, timeout_cb, 2, 0.);  ev_timer_start (loop, &timeout_watcher);   // 启动 eventloop  ev_run (loop, 0);   return 0;}  
libev 用 watcher 来检测各种事件,当事件发生时,会调用 watcher 的回调函数。
那么,具体支持哪些事件类型呢?
如果你对 libev 感兴趣,可以根据下面这张图阅读其源码:


功率因数校正在能量收集系统功效和质量方面的应用
交直流充电桩测试仪介绍PROFITEST H+E PACKAGE介绍
详解89-03KA-8C传感器的实现途径
智慧温室大棚系统的主要组成部分都有哪些系统
压敏电阻器32D391k广泛应用与电焊机行业
关于Eventloop的概念
透析Uber匹兹堡计划:一场30万人的无人驾驶公共测试
如何在滑动开关应用中使用感应开关
虹科分享 | 专为创意专业人士设计的Thunderbolt适配器
Testbench的基本组成和设计规则
RFID技术是包装行业智能化的杀手锏
无线充电功率限制提升到80瓦?ST方案帮你抓住先机
adau1701原理图与adau1701开发板原理图
微软已经推出了最新的Windows 10 Insider Preview版本
当前微型电动汽车的市场价值如何
电话机器人的应用让我们的工作变得更简单
高频变压器的生产制作规范
关于被动同心转向式多履带全向移动机器人的设计
手机红外技术的优缺点
基于义齿压力测量的微型电容式传感器研制工艺及封装测试