同步IO和异步IO
IO操作一般分成两个不同的阶段:
- 等待数据准备好
- 从内核向进程复制数据
比如说对于网络IO:
- 第一步通常是等待数据从网络中到达,然后复制到内核中的某个缓冲区。
- 把数据从内核缓冲区复制到应用进程缓冲区。
比如说对于系统调用read:
- 内核把数据在内核缓冲区中准备好。
- 然后把它复制到进程IO缓冲区。
而对于标准IO来说,还多了一个标准IO缓冲区。它们的设置是为了减少调用erad和write的次数。
同步IO操作导致请求进程阻塞,直到IO完成为止。在同步IO中,真正的IO操作会阻塞进程。不管是阻塞IO还是非阻塞IO,以及IO多路复用,信号驱动的IO模型,都是同步IO。
异步IO操作不导致请求进程阻塞,即使真正的IO操作也不会阻塞。相对于信号驱动的IO,内核通知我们的是什么时候可以启动一个IO操作,而异步IO模型是内核通知我们IO操作什么时候完成。
阻塞IO
所有的套接字都是阻塞的。从数据复制到内核,以及从内核复制到应用程序缓冲区,都是阻塞的。
非阻塞IO
非阻塞IO的意思是告诉内核如果当前的操作如果不能立即返回,而是要sleep才能完成时,返回一个错误。
等到某一次查询,数据已经准备了,然后进行相应的IO操作。
select和poll,epoll
IO复用模型的思想是同时处理多个文件描述符。
select和pselect
selecdt返回的条件:
- 等待的描述符准备好(读准备好,写准备好,异常准备好)只有两个异常的条件。
- 超时
满足任意一个就行。
poll
epoll
信号驱动的IO
利用信号,让内核在描述符就绪时发送SIGIO通知应用程序,然后调用相应的处理程序进行IO操作。
异步IO
内核把数据准备好,然后复制到应用程序缓冲区之后才通知我们。这个时候IO操作已经完成了。
记录锁
记录锁可以用来同步。打开一个空文件,使用第一个字节作为锁字节。要访问资源,需要对该字节加锁,要释放资源,需要对该字节解锁。
所以一个文件可以实现多个锁。
readv和writev
readv从文件描述符指定的文件中读取相应的数据到多个缓冲区。
writev将多个缓冲区中的内容写入文件描述符中。
readn和writen
适用于已经知道要读取和写入的字节数量的情景。其实就是多次调用非阻塞的read和write进行操作。
存储映射IO
mmap将一个磁盘文件映射到存储空间的一个缓冲区上。从缓冲区读,就相当于读文件中的相应字节。从缓冲区写,就相当于写文件中的相应字节。
参考文献
1.《APUE》第三版
2.《UNP》卷一