文章目录
- 操作系统I/O:阻塞和非阻塞
- 调用阻塞I/O时,应用程序需等待I/O完成才返结果
- 调用非阻塞I/O为调用之后立即返回,
- 轮询技术主要有以下四种:
- select
- poll
- epoll
- kequeue
- 参考链接
- 阻塞和非阻塞系统调用
- 阻塞
- 非阻塞
- 参考链接
操作系统I/O:阻塞和非阻塞
- OS内核对于I/O只有两方式:阻塞和非阻塞。
调用阻塞I/O时,应用程序需等待I/O完成才返结果
- 调用之后要等到系统内核层面完成所有操作后,调用才结束。
调用非阻塞I/O为调用之后立即返回,
- 返回后
- CPU的时间片可用来处理其他事务,此时性能是提升的。
- 问题是:
- 由于完整的I/O没完成,立即返回的并不是业务层期望的数据,而仅仅是当前调用的状态。
- 为获取完整的数据,程序需要重复调用I/O操作来确认是否完成。
- 这种重复调用判断操作是否完成的技术叫做轮询
轮询技术主要有以下四种:
- read
- 最原始、性能最低,
- 重复调用来检查I/O的状态来完成完整数据的读取。
- 在得到数据前,CPU一直耗在等待上。
select
- 改进read,通过对文件描述符上的事件状态来进行判断。
- 有一个较弱的限制为
- 它采用一个1024长的数组存储状态,
- 所以最多可同时检查1024个文件描述符。
poll
- 对select改进,采用链表方式避免数组长度的限制,其次它能避免不需要的检查。
- 但当文件描述符较多时,它性能还是低。
epoll
- LInux下效率最高的I/O事件通知机制,在进入轮询的时候如果没有检查到I/O事件,将会进行休眠,直到事件发生将它唤醒。
- 它是真实利用了事件通知、执行回调的方式,而不是遍历查询,所以不浪费CPU,执行效率高。
kequeue
- 与epoll类似,仅FreeBSD系统下存在。
阻塞和非阻塞系统调用
阻塞
- 调用结果返回之前,当前线程会被挂起。
- 函数只有在得到结果之后才会返回。
- 有人把阻塞调用和同步调用等同起来,实际上是不同的。
- 对同步调用来说,很多时候当前线程还是激活的,只是从逻辑上当前函数有返回而已。
- 例如,我们在CSocket中调用Receive函数,如果缓冲区中没有数据,这个函数就会一直等待,直到有数据才返回。
- 而此时,当前线程还会继续处理各种各样的消息。
- 如果主窗口和调用函数在同一个线程中,除非你在特殊的界面操作函数中调用,其实主界面还是应该可以刷新。
- socket接收数据的另外一个函数recv则是一个阻塞调用的例子。
- 当socket工作在阻塞模式的时候,如果没有数据的情况下调用该函数,则当前线程就会被挂起,直到有数据为止。
非阻塞
- 指在不能立刻得到结果之前,该函数不阻塞当前线程,立刻返。
- 对象的阻塞模式和阻塞函数调用 对象是否处于阻塞模式和函数是不是阻塞调用有很强的相关性,但并不是一一对应。
- 阻塞对象上可以有非阻塞的调用方式,可通过API去轮询状态,在适当时调用阻塞函数,就可避免阻塞。
- 对非阻塞对象,调用特殊的函数也可进入阻塞调用。
- 函数select就是这样的一个例子。