1.阻塞 blocking

调用者调用了某个函数,等待这个函数返回,期间什么也不做,不停的去检查这个函数有没有返回,必须等这个函数返回才能进行下一步动作

线程(或进程)处于阻塞状态不消耗CPU,但是线程(进程)不能干其他事情

2、非阻塞

非阻塞等待,每隔一段时间就去检测IO事件是否就绪。没有就绪就可以做其他事。非阻塞I/O执行系统调 用总是立即返回,不管事件是否已经发生,若事件没有发生,则返回-1,此时可以根据 errno 区分这两 种情况,对于accept,recv 和 send,事件未发生时,errno 通常被设置成 EAGAIN。

Linux上的五种IO模型_多路复用

一般采用while轮询的方式,当缓冲没有数据到达,可以干其他事情。比较消耗系统资源。通过fcntl可以设置非阻塞。比如:有10000个客户端要发送数据,每一次循环将有10000次系统调用。

3、IO复用

Linux用select/poll/epoll函数实现IO复用模型,这些函数也会使进程阻塞,但是和阻塞IO所不同的是这些函数可以同时阻塞多个IO操作。而且可以同时对多个读操作、写操作的IO函数进行检测。直到有数据可读或可写时,才真正调用lO操作函数。

Linux上的五种IO模型_数据_02

可以同时检测多个IO,一般交给内核来完成监测工作,当有数据到达时,就通过应用程序调用read进行数据读写。可以理解为是非阻塞、忙轮询方式的一种改进。在一个线程或进程中可以同时检测多个客户端

4、信号驱动

Linux 用套接口进行信号驱动 IO,安装一个信号处理函数,进程继续运行并不阻塞,当IO事件就绪,进 程收到SIGIO 信号,然后处理 IO 事件。

Linux上的五种IO模型_数据_03

通过SIGIO信号来处理,当数据准备好之后,发送该信号,然后捕捉该信号并调用read进行数据读写 。

内核在第一个阶段是异步,在第二个阶段是同步;与非阻塞IO的区别在于它提供了消息通知机制,不需 要用户进程不断的轮询检查,减少了系统API的调用次数,提高了效率。

问题:IO多路复用和信号驱动有什么区别?不都是当数据准备好的时候通知程序对缓冲区里的数据进行处理吗?答: 多路复用是内核监听多个文件描述符,在监听的函数处阻塞比如select, 拷贝数据也是阻塞的,多路复用只是防止进程在某个io阻塞后,不能及时处理其他io的事件。信号驱动则是先登记信号处理函数,当数据准备完毕后由内核发送信号给进程,让进程处理。信号驱动不阻塞在数据准备过程,但阻塞在数据拷贝,所以两者都是同步IO

5、异步

Linux中,可以调用 aio_read 函数告诉内核描述字缓冲区指针和缓冲区的大小、文件偏移及通知的方 式,然后立即返回,当内核将数据拷贝到缓冲区后,再通知应用程序。

Linux上的五种IO模型_数据_04

内核完成监听和读写操作,当数据读写完成,通知应用程序处理数据。