Skip to content

Latest commit

 

History

History
179 lines (147 loc) · 7.67 KB

LinuxIO模型.md

File metadata and controls

179 lines (147 loc) · 7.67 KB

LinuxIO模型

目录

概念说明

首先理解下面概念

  • 用户空间和内核空间
  • 进程切换
  • 进程的阻塞
  • 文件描述符fd
  • 缓存I/O

用户空间和内核空间

现代操作系统采用虚拟存储器, 那么对32位操作系统而言, 它的寻址空间(虚拟存储空间)为4G(2^32)
操作系统的核心是内核, 不同于普通的应用程序, 内核可以访问受保护的内存空间, 也拥有访问底层硬件设备的所有权限
为了保证用户进程不能直接操作内核, 保证内核的安全, 操作系统将虚拟空间划分为两部分: 内核空间和用户空间

针对Linux系统而言, 将最高的1GB字节(从虚拟地址0xC0000000~0xFFFFFFFF), 供内核使用, 称为内核空间(Kernel Space)
而将较低的3GB字节(从虚拟地址0x00000000~0xB0000000), 供各个进程使用, 称为用户空间(User Space)

简单来说, 内核空间是内核代码运行的地方, 用户空间是用户程序代码运行的地方
为了安全, 内核空间和用户空间是隔离的, 即使用户的程序崩溃了, 内核也不受影响
Linux系统的一次IO操作, 数据不会直接拷贝到用户空间缓冲区, 而是分为两个阶段:
(1)内核空间准备数据
(2)将数据从内核空间缓冲区拷贝到用户空间缓冲区

LinuxIO

进程切换

什么是进程切换?
为了控制进程的执行, 内核必须有能力挂起正在CPU上运行的进程, 并恢复以前挂起的某个进程的执行, 这种行为被称为进程切换
因此可以说, 任何进程都是在操作系统内核的支持下进行的, 是与内核紧密相关的

什么是PCB?
进程控制块(PCB)是系统为了管理进程设置的一个专门的数据结构, 系统用它来记录进程的外部特征, 描述进程的运动变化过程
同时, 系统可以利用PCB来控制和管理进程, 所以说, PCB(进程控制块)是系统感知进程存在的唯一标志

从一个进程切换到另外一个进程, 这个过程经过下列变化:
1. 保存处理机上下文, 包括程序计数器和其他寄存器
2. 更新PCB信息
3. 将进程的PCB移入相应的队列, 如就绪、在某事件阻塞等队列
4. 选择另一个进程执行, 并更新其PCB
5. 更新内存管理的数据结构
6. 恢复处理机上下文

进程的阻塞

什么是进程的阻塞?
正在执行的进程, 由于期待的某些事件未发生, 
如请求资源失败、等待某种操作的完成、新数据尚未到达或无新工作做等,
则由系统自动执行阻塞原语(Block), 使自己由运行状态变为阻塞状态

特点?
1. 只有处于运行状态的进程(获得CPU), 才能被阻塞
2. 进程的阻塞是进程自身的一种主动行为
3. 当进程进入阻塞状态, 不占用CPU资源

文件描述符fd

fd: file descriptor
每个进程在PCB中保存着一份文件描述符表, 文件描述符表中每一项都有一个指向已打开文件的指针
文件描述符表的索引就是文件描述符
当程序打开一个现有文件或者创建一个新文件时, 内核向进程返回一个文件描述符

linux-fd

缓存I/O

什么是缓存I/O?
缓存I/O又称为标准I/O, 大多数文件系统的默认I/O操作都是缓存I/O
操作系统使用read把数据从内核缓冲区复制到进程缓冲区, 使用write把数据从进程缓冲区复制到内核缓冲区

缓存I/O的优点?
读: 一次读入大量数据放入缓冲区, 需要的时候从缓冲区取得数据
写: 把要写入的数据暂存在缓冲区中, 积累到一定数量再一次性写入, 不是每次的write操作都会导致内核的写操作
提高了磁盘的I/O效率

缓存I/O的缺点?
数据在传输过程中需要在进程缓冲区和内核缓冲区之间进行多次数据拷贝操作, 导致CPU和内存的开销

Linux的5种IO模型

网络IO的本质是读取socket, socket在Linux系统中被抽象成流, IO可以理解为对流的操作
对于一次IO操作, 分为两个步骤:

  • 过程-: 内核空间准备数据
  • 过程二: 将数据从内核空间缓冲区拷贝到用户空间缓冲区
# Linux的5种IO模型
1. 阻塞IO: BIO, blocking IO
2. 非阻塞IO: NIO, nonblocking IO
3. 多路复用IO: IO multiplexing
4. 信号驱动IO: signal driven IO
5. 异步IO: asynchronous IO

阻塞IO

阻塞IO

用户进程调用一个IO函数, 导致应用程序阻塞, 直到过程一和过程二完成以后, IO函数返回成功指示, 用户进程解除block的状态

阻塞IO在IO执行的两个阶段都被block, 在等待数据返回的过程中不能进行其他操作

非阻塞IO

非阻塞IO

我们把SOCKET接口设置为非阻塞就是告诉内核, 当调用IO函数而内核空间数据未准备好时,
不要将进程睡眠, 而是返回一个EWOULDBLOCK错误, 这样进程反复调用IO函数进行轮询, 
直到内核空间数据准备好, 然后数据被拷贝到用户空间缓冲区, IO函数返回成功指示, 应用进程开始处理数据

过程一需要不断的进行轮询, 不是阻塞状态
过程二阻塞

多路复用IO

多路复用IO

多路复用IO会用到 select、poll、epoll 函数, 这几个函数会使进程阻塞
但是和阻塞IO不同的是, 这几个函数可以同时阻塞多个IO操作, 直到有数据可读或可写时, 才真正调用IO函数

过程一是阻塞在select、poll、epoll 函数, 而真正的IO函数recvfrom是非阻塞的
过程二阻塞

信号驱动IO

信号驱动IO

我们首先设置socket为一个信号驱动IO, 并且通过sigaction sytem call安装一个信号处理函数signal handler, 进程继续运行并不阻塞
当内核空间准备好数据后, 进程会收到一个SIGIO信号, 可以在信号处理函数中调用IO操作函数处理数据

过程一不阻塞
过程二阻塞

异步IO

异步IO

当一个异步过程调用发出后, 调用者不能立刻得到结果, 实际处理这个调用的部件在完成后,
通过状态、通知和回调来通知调用者的输入输出操作

过程一和过程二都不阻塞

五个IO模型的比较

五个IO模型的比较

阻塞IO、非阻塞IO、多路复用IO、信号驱动IO 都属于同步IO, 只有异步IO才是异步IO

阻塞IO和非阻塞IO的区别: 过程一(内核空间准备数据)进程是否阻塞
同步IO和异步IO的区别: 过程二(将数据从内核空间缓冲区拷贝到用户空间缓冲区)进程是否阻塞

参考