【IO模型探讨】阻塞,非阻塞,同步,异步

来源:互联网 发布:miss淘宝店网址多少 编辑:程序博客网 时间:2024/05/23 17:56

以前看这部分内容的时候没仔细理清楚,只知其一,不知其二。最近在学习高性能服务器编程时,又碰到同步和异步的问题,所以看了一些资料学习了一下,做一个总结。

IO模型一共有五种:

阻塞IO

非阻塞IO

IO复用

信号驱动IO

异步IO

为了理清楚这五种IO模型的工作原理,用一个read函数来做假设,一次read函数调用会经历两个阶段:

1、等待内核缓冲区有数据可读;

2、将数据从内核缓冲区读到到用户缓冲区。


阻塞IO

当用read函数来读取某个文件描述符时,先进入第一阶段,判断内核缓冲区有无数据可读,若有数据可读,则直接进行第二阶段,将数据从内核缓冲区读到用户缓冲区中。若此时没有数据,则read函数会被挂起,该进程被阻塞住,不再往下执行。一旦内核缓冲区有可以读取的数据了,read函数将会被唤醒,接着执行第二阶段,将数据从内核缓冲区读到用户缓冲区中,此时进程不在阻塞,继续往下执行。


非阻塞IO

非阻塞IO是通过fcntl函数将文件描述符设置为O_NONBLOCK来实现的。当read函数执行时,若此时内核缓冲区没有数据,则read函数立即返回-1,并设置errno为EWOULDBLOCK,意思是期望阻塞,然后会再次执行read操作,所以read并没有被挂起。直到内核缓冲区中有数据可读时,将数据拷贝到用户缓冲区,然后返回。


IO复用

通常是指我们所用的select,poll,epoll函数。这三个函数本身是阻塞的,它们可以同时监听多个文件描述符的事件,如果监听的某个文件描述符有可读事件发生,则保证能立即read到数据,并返回,所以此时read是阻塞还是非阻塞无关紧要,因为肯定会读到数据。

当调用select时,会向内核注册一组事件,然后进程会被阻塞住,内核监听这组事件,如果有某个可读事件发生时,select立即返回,进程调用read保证能读到数据(包括0字节数据,此时对方关闭了链接),然后将数据从内核缓冲区读到用户缓冲区。


信号驱动IO (用的不多,只进行简单探讨)

SIGIO信号也可以用来报告IO事件。我们可以为一个文件描述符指定宿主进程,当这个文件描述符有可读事件发生时,宿主进程将会捕捉到SIGIO信号,信号处理函数就会被执行,然后可以在这个信号处理函数中进行read操作,并且保证能读到数据(包括0字节数据)。


异步IO

当read函数执行后,什么也不管,也不会读取数据,立即返回,即使这个文件描述符是阻塞的也立即返回,然后程序接着做其它事情。将IO操作完全交给内核来处理,当内核缓冲区有数据可读时,内核负责把这些数据拷贝到用户缓冲区,然后给进程发送一个信号,告诉进程read操作完成了,异步IO就是如此简单。


同步IO和异步IO

阻塞,非阻塞,IO复用,信号驱动IO都是同步IO模型。为什么是同步的,因为程序总是会在某一个时间知道内核有数据可以读取了,然后进程自己将数据从内核缓冲区拷贝到用户缓冲区中。

那什么是异步IO呢,毫无疑问就是,进程自己并不知道何时内核有数据可以读取了,因为它完全交由内核来处理了,内核负责将数据从内核缓冲区拷贝到用户缓冲区,然后发信号通知进程。

0 0
原创粉丝点击