基本概念
- 文件描述符(file descriptor):用于表述指向文件的引用的抽象化概念。文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。
- 缓存I/O:操作系统会将I/O的数据缓存在文件系统的页缓存中,也就是说,数据会先被拷贝到操作系统内核的缓冲区中, 然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间。
I/O操作两阶段(read)
- 数据准备阶段:发起I/O请求,操作系统将数据从磁盘拷贝到内核缓冲区。
- 内核空间拷贝到进程空间阶段,将数据从内核缓冲区拷贝到进程的地址空间。
阻塞和非阻塞
描述的是调用方在第一阶段的状态(准备数据时调用方状态)。
- 阻塞:调用方发起I/O请求后一直阻塞等待,直到被调用数据准备完成。
- 非阻塞:调用方发起I/O请求后不管数据是否准备完成立即返回不一致阻塞,然后采用轮询或其他方式获取结果。
同步和异步
描述的是在第二阶段被调用方的状态(数据准备完成后被调用方状态)。
- 同步:被调用方一直等待数据从内核缓冲区拷贝到程序地址空间后才会返回结果给调用方。
- 异步:被调用方先返回结果给调用方,等待数据从内核缓冲区拷贝到程序地址空间后再通过回调函数或产生某个信息来通知调用方。
五种常用I/O模型
同步阻塞I/O模型
进程发起I/O请求后会一直阻塞等待,直到数据拷贝到进程地址空间。进程在一、二阶段都处于阻塞状态。
同步非阻塞I/O模型
进程发起I/O请求后如果数据还未准备成功会先返回进行其他操作,通过轮询的方式定时获取数据准备结果。数据准备成功后阻塞等待,直到数据拷贝到进程地址空间。进程在第二阶段是阻塞状态。
I/O多路复用模型
I/O多路复用是指进程可以同时监控多个文件描述符,内核如果准备好其中的数据就会通知相应进程。进程在第二阶段是阻塞状态。
- 进程调用select或者poll监听指定文件描述符,返回结果进程不会阻塞等待。
- select/poll会轮询所有监听的文件描述符,如果发现有准备好的数据就将相应的fd放进fd_set中最后返回这些fd,并通知进程将这些数据拷贝到进程地址空间。
总结:I/O多路复用模型本质是同步非阻塞I/O模型,与同步非阻塞I/O模型的区别在于I/O多路复用可以实现一个进程或线程同时监控多个socket,适用于高并发。
信号驱动I/O模型
进程调用sigaction函数注册相应fd的信号函数,然后返回结果进程继续执行,等数据准备完成后内核执行信号函数通知进程将数据从内核缓存拷贝到进程地址空间中。由于仍然需要等待数据从内核缓存拷贝到进程地址空间,所以本质是同步非阻塞I/O模型,区别在于获取数据准备成功的信号的方式不同(前者轮询)。进程在第二阶段是阻塞状态。
异步I/O模型
进程调用aio_read通知内核准备数据,并将准备好的数据拷贝到指定进程地址空间中,最后执行指定的函数或产生一个信号通知进程。该种模型在第一、二阶段均没有阻塞,所以是异步非阻塞。
总结
阻塞IO模型、非阻塞IO模型、IO复用模型(select/poll/epoll)、信号驱动IO模型都属于同步IO,因为阶段2是阻塞的。