Linux IO模型

由于I/O模型现在掌握还不够透彻,本文仅列出了一些I/O模型中的一些常用概念,对于select、poll、epoll和信号驱动I/O等模型理解还不够透彻,待理解透彻后补上。

阻塞I/O与非阻塞I/O

阻塞I/O:当进行I/O操作后,程序处于等待状态,直到需要的资源可用为止。

非阻塞I/O:当进行I/O操作后,函数直接返回,不需要等待。

两种文件描述符准备就绪的通知模式

水平触发通知:如果文件描述符上可以非阻塞地执行I/O系统调用,此时认为它已经就绪。允许在任意时刻重复检测I/O状态,没有必要每次当文件描述符就绪后尽可能多的执行I/O。其中select()和poll()属于水平触发通知模式。

边缘触发通知:如果文件描述符自上次状态检查以来有了新的I/O活动,此时需要触发通知。只有当I/O事件发生后才会得到通知,在另外一个I/O事件到来之前不会得到通知。因此,在接收到一个I/O事件后,程序在某个时刻应该在相应的文件描述符上尽可能多地执行I/O。每个被检查的文件描述符被置为非阻塞模式,在得到I/O事件通知后重复执行I/O操作,直到系统调用返回错误为止。其中信号驱动I/O属于此种类型。

将的通俗一点,假设通过异步I/O读取socket数据,当接收到100个字节的数据后,这时候会触发通知给应用程序。如果应用程序仅读取了50字节的数据,重新调用异步I/O函数时,在水平触发时仍然会得到通知,而采用边缘触发时不会得到通知。

epoll即可以采用水平触发通知方式,也可以采用边缘触发通知方式。

这两个概念对于理解Linux的I/O模型非常重要,但是却是不容易理解。可以通过举例说明:一个管道内收到了数据,注册该管道描述符的epoll返回,但是用户只读取了一部分数据,然后再次调用了epoll。这时,如果是水平触发方式,epoll将立刻返回,因为当前有数据可读,满足IO就绪的要求;但是如果是边沿触发方式,epoll不会返回,因为调用之后还没有新的IO事件发生,直到有新的数据到来,epoll才会返回,用户可以一并读到老的数据和新的数据。

同步I/O与异步I/O

同步I/O:发出I/O操作后,后面操作不能进行,要么等待I/O操作完成,要么放弃I/O操作。后面的操作和当前的操作只能有一个进行。

异步I/O:发出I/O操作后,马上返回继续执行后面的操作,而I/O操作同时执行。

参考文章