Unix IO模型学习

这季度学习java nio及其相关的内容和框架,所以就想先看看Unix下的一些IO模型。结合网络上的资料进行学习,自己也写篇日志,加强一下理解吧。

POSIX中对同步IO和异步IO的规定

同步IO操作:引起进程的阻塞直到IO操作完成异步IO操作:IO操作不会引起进程阻塞

在UNIX下,有5中操作模型

阻塞IO非阻塞IOIO复用信号驱动IO异步IO

按照网络上的说法,前四种是属于同步IO,第五种才属于异步IO,对于这个结论,我的理解是根据用户进程是否阻塞来判断的(而不是内核进程)。关于同步和异步的一些讨论,可以参考http://bbs.chinaunix.net/viewthread.php?tid=947563

阻塞IO

这是我们熟悉的IO模型,一个进程在作IO操作时,非要等到数据从内核空间拷贝到用户进程空间,才会返回。这个模型的优点就是简单,而且在阻塞的时候,CPU还可以进行调度,去执行别的进程。

非阻塞IO

一开始我看是非阻塞IO,觉得应该要比阻塞IO模型先进,可是当我一看使用方法的时候,就知道这个模型是不会被实际使用的,仅仅只能作为理论上存在的IO模型。这个模型的观点是:进行IO操作的时候,不阻塞,如果没有数据准备好,就直接返回错误码(或者是别的代码)。因此,使用者就只能不断进行轮询来调用IO函数。这样的后果就是,不仅在宏观上形成了与阻塞IO一共的“阻塞”效果,而且在微观上,CPU一直被用来轮询,造成了CPU的浪费。所以,这个模型还不如阻塞IO模型实用。

IO复用

对于IO复用,我的理解有三点:

在一次系统调用中,实现了询问多个描述符的IO准备情况 ―― 根据事件通知为了实现第一点,就需要把阻塞的地方进行转移。把一次系统调用,分为两次系统调用。第一次系统调用可以询问多个描述符的IO准备情况,在这个地方进行阻塞;而第二次系统调用,是针对已经准备好IO的描述符进行调用,此时,理论上(按照我的理解),也是会发生阻塞的,只不过是此时内核已经把数据准备好了,阻塞的时间可以忽略不计罢了。本质上,还是阻塞的。

信号IO

我们都知道,信号是UNIX提供了进程间进行通信的一种方式。我们常用的 kill -9 命令(kill是向进程传递信号量,9只是众多信号中的一个代号),或者是 Ctrl + C 的时候,就是向某个进程发出终止的信号,这样进程就退出了。

而对于信号IO的模型,我是这么理解的:进程在发起IO操作,系统调用之后,直接访问,内核会在IO数据准备好之后,以某个信号通知发起IO操作的进程,从而使得该进程的信号处理函数可以读取IO数据的操作。

本质上,这也是阻塞的IO模型,因为在信号处理函数中,同样也是要进行阻塞的,只是在在这个时候发起系统系统,内核已经把数据准备好了。

异步IO

这是真正的异步IO了。实现的机制是:用户在发起异步IO的系统调用时,会把相应的数据处理函数作为回调函数,等到IO数据准备好,内核会主动调用此回调函数。可以看出,用户进程在这种模型下,只调用了一次系统调用,而且是立即返回的,因此,就不会出现让进程阻塞的情况,也就符合了POSIX中异步IO的定义。

其实我理解起来,思路是和信号IO差不多的,唯一不同的地方,对于IO数据的操作,异步IO是由内核主动发起的,而信号IO是由用户进程发起的。

以上是我结合网络资料,对UNIX IO模型的一些学习和理解,如果有错误或者不当的地方,请随时留言指出,谢谢!

Comment are closed.