1. 概念简述

内核空间和用户空间:

​ 内核空间:内核调控的硬件资源空间。

​ 用户空间:基于内核提供的环境的应用程序的活动空间,。

同步和异步:两者的状态关系

​ 同步:双方都在同一时间段围绕同一任务行动(调用者等待,被调用者处理),只有当前任务结束,才可以进行下一个。

​ 异步:双方无需同一时间段围绕同一任务行动,调用者只需通知被调用者处理,之后可自由行动。调用者处理完成后返回结果。

阻塞和非阻塞:自身状态

​ 阻塞:一直等待,直至得到结果返回。

​ 非阻塞:不用等待,可以去做其他事情。

水平触发和边缘触发:多路复用中的两种模式

​ 水平触发:当FD已经准备就绪可以进行非阻塞的执行I/O操作时触发通知。

​ 边缘触发:当FD自上次状态改变后有新的IO活动到来时触发通知。

2. I/O模型

共五种,同步阻塞I/O,同步非阻塞I/O,I/O复用,信号驱动I/O和异步I/O:

  • 同步阻塞I/O:

    发起后一直等待,直到完成

  • 同步非阻塞I/O

    发起后进程可以做其它事情,不过会一直询问,直到完成。

  • I/O多路复用模型

    阻塞多个I/O操作,直到数据准备好才调用I/O操作函数

  • 信号驱动I/O

    需要安装一个信号函数,进程运行不阻塞,数据准备好后发送进程一个SIGIO信号,可以在信号处理函数中调用I/O操作函数。

  • 异步非阻塞I/O

    发起后去做其他事情,完成后被调用者通知调用者。缺点是非常消耗CPU资源。

3. I/O多路复用详解

​ I/O多路复用又称异步阻塞模型,从可阻塞多个I/O操作,提升执行效率。主要实现方式有三种:select,poll和epoll。

3.1 select

​ 将fd集合从用户空间copy到内核空间,无差别轮询所有流,找出所有能读出数据或写入数据的流来进行操作。select单个进程能够监视的FD数量存在最大限制,但可以更改(内核源码中的#define __FD_SETSIZE),通常是1024,但由于采用轮询的方式扫描FD,时间复杂度为O(n),所以FD数量越多,性能越差。两次内核空间和用户空间的拷贝需要copy大量的FD数据结构,开销较大。采用水平触发方式,如果应用程序没有完成一个已经ready的文件描述符进行I/O操作,那么之后select调用还是会返回这些FD。在监听事件时告诉内核要监听什么类型的事件。

3.2 poll

​ 使用链表保存FD,因此没有了数量限制,但其它缺点依然存在。

3.3 epoll

​ event poll,事件驱动,使用一个FD管理多个FD。可以采用水平触发,也可以使用边缘触发。在监听事件之前对其类型进行注册,并把所有的FDcopy进内核,且为每个FD指定一个回调函数,将符合条件的fd放到一个链表中,epoll_wait的操作就是定期查看判断这个链表,有FD的话就调用其指定的回调函数。