libeio源码分析 – 主流程
来源:互联网 发布:诸葛亮马前课指算法图 编辑:程序博客网 时间:2024/05/22 13:07
libeio源码分析 – 主流程
@淘宝千石
简介
This library provides fully asynchronous versions of most POSIX functions dealing with I/O. Unlike most asynchronous libraries, this not only includes read and write, but also open, stat, unlink and similar functions, as well as less rarely ones such as mknod, futime or readlink. It also offers wrappers around sendfile (Solaris, Linux, HP-UX and FreeBSD, with emulation on other platforms) and readahead (Linux, with emulation elsewhere>). The goal is to enable you to write fully non-blocking programs.
缘起
相信上面这段话已经将libeio的feature讲的足够清楚:提供全套异步文件操作的接口,让使用者能写出完全非阻塞的程序。阻塞意味着低效,但非阻塞一定要有很好的通知机制才能做到高效。
其实linux下的AIO(异步IO)并不是没有解决方案:在用户态,多线程同步来模拟的异步IO,如Glibc 的AIO;以及在内核态实现异步通知,如linux内核2.6.22之后实现的Kernel Native AIO。但两者都存在让使用者望而祛步的问题。
Glibc的AIO bug太多,而且IO发起者并不是最后的IO终结者(callback是在单独的线程执行的);而kernel Native AIO只支持O_DIRECT方式,无法利用Page cache。
正是由于上述原因,Marc Alexander Lehmann大佬决定自己开发一个AIO库,及libeio。libeio也是在用户态用多线程同步来模拟异步IO,但实现更高效,代码也更可靠,目前虽然是beta版,但已经可以上生产了(node.js底层就是用libev和libeio来驱动的)。还要强调一点:libeio里IO的终结者正是当初IO的发起者(这一点非常重要,因为IO都是由用户的request而发起,而IO完成后返回给用户的response也能在处理request的线程中完成)。
实现
一次异步IO操作可以分为三个阶段:
初始化 –> 提交IO –> 通知worker线程 (主线程);
取request –> 执行IO –> 通知主线程 (worker线程);
取response –> callback –> 结束IO (主线程)。
下面我们通过一张流程图来剖析一下libeio的源码实现。
1. 主线程调用eio_init函数,主要是初始化req_queue,res_queue以及对应的mutex和cond;
2-3. 所有的IO操作其实都是对eio_sumbit的调用,而eio_sumbit的职能是将IO操作封装为request并插入到req_queue;并调用cond_signal向worker线程发出reqwait已经OK的信号;
libeio处理流程图
4. worker线程被创建后执行的函数为etp_proc,etp_proc启动后会一直等待reqwait条件的出现;
5-6. 当reqwait条件变量满足时,etp_proc从req_queue中取得一个待处理的request;并调用eio_execute来同步执行该IO操作;
7-8. eio_execute完成后,将response插入到res_queue队列中;同时调用want_poll来通知主线程request已经处理完毕;
9. 这里worker线程通知主线程的机制是通过向pipe[1]写一个byte数据;
10. 当主线程发现pipe[0]可读时,就调用eio_poll;
11. eio_poll从res_queue里取response,并调用该IO操作在init时设置的callback函数完成后续处理;
12. 在res_queue中没有待处理response时,调用done_poll;
13-14. done_poll从pipe[0]读出一个byte数据,该IO操作完成。
后记
libeio的实现就是这么简洁,这里需要说明两点:
1. 在worker线程完成IO请求,通知主线程的机制是需要使用者自定义的,wait_poll和done_poll就是libeio提供给使用者的接口(pipe是一种常用的线程通知机制)。
2. worker线程并不是为每个请求都创建一个,而是维护了一个worker线程池,关于这部分将会在下面的文章中单独讲到。
参考
《libeio接口文档》
http://pod.tst.eu/http://cvs.schmorp.de/libeio/eio.pod
《linux异步IO浅析》
http://hi.baidu.com/_kouu/blog/item/e225f67b337841f42f73b341.html
《linux AIO (异步IO) 那点事儿》
http://club.cnodejs.org/topic/4f16442ccae1f4aa270010a7
- libeio源码分析 – 主流程
- libeio源码分析 – 主流程
- fastdfs源码分析2-storage主流程
- fastdfs源码分析3-tracker主流程
- zookeeper的选主流程(源码分析)
- APM源码分析之 主流程
- cocos2d-x源码分析::主流程(mainloop)分析
- 【OVS2.5.0源码分析】datapath之主流程分析
- IK分词源码分析连载(一)--主流程
- Nginx源码分析 - 主流程篇 - Nginx的启动流程
- Nginx源码分析 - 主流程篇 - 全局变量cycle初始化
- Nginx源码分析 - 主流程篇 - 模块的初始化
- Nginx源码分析 - 主流程篇 - 解析配置文件
- Nginx源码分析 - 主流程篇 - 多进程实现
- 【OVS2.5源码解读】datapath主流程分析
- uboot 主流程分析
- sqoop 抽取源码流程分析(一) 主流程分析以及各种插件
- nginx源码浅析--主流程
- 孙鑫VC++第11章图形的保存和重绘
- Android 日记之二 pendingIntent简单理解
- linux后端服务程序之信号处理
- Eclipse cvs repositories使用及目录结构说明
- view.WindowManager$BadTokenException: Unable to add window…is not valid; is your activity running?
- libeio源码分析 – 主流程
- 整数划分问题(苹果盘子问题)
- 孙鑫VC++第12章文件和注册表操作
- Redis skip list结构分析
- mac开发中使用SDWebImage
- 智.畅行导航仪(CX-2010)安装凯立德MIPS导航软件
- Java编程高级之Java网络编程知识基础
- 什么是java泛型
- Java编程高级之UDP协议编程在Java中的体现