IO Buffering And Spooling
缓冲区是什么
缓冲区是一个临时存储区域,可以由硬件寄存器组成,也可以由主存中的一段空间组成。操作系统 I/O 管理讨论的缓冲区通常是主存缓冲区,由设备独立性软件组织和管理。
缓冲区的作用:
- 缓和 CPU、内存与 I/O 设备之间的速度差异;
- 协调不同设备或进程之间的数据单位差异;
- 减少进程因 I/O 等待而被频繁阻塞;
- 支持异步 I/O、DMA、SPOOLing 等机制。
以输出为例,用户进程可以把一块数据快速放入缓冲区,之后继续执行;慢速设备再从缓冲区逐步取走数据。输入时方向相反,设备先把数据放入缓冲区,进程再从缓冲区取数据。
单缓冲
单缓冲是在主存中为 I/O 分配一个缓冲区。若题目没有特别说明,一个缓冲区大小通常等于一个数据块。
单缓冲读入时涉及三个时间:
| 符号 | 含义 |
|---|---|
| $T$ | 设备把一块数据输入到缓冲区的时间 |
| $M$ | 缓冲区到用户工作区的传送时间 |
| $C$ | CPU 处理用户工作区中一块数据的时间 |
单缓冲约束:
- 缓冲区非空时,不能继续向缓冲区输入,只能先把数据传出;
- 缓冲区为空时,可以向缓冲区输入;
- 通常要等缓冲区装满一块数据后,才能传送到用户工作区。
分析平均时间时,不要先背公式。先选一个便于观察的状态,再看系统什么时候再次回到这个状态。两次相同状态之间处理了多少块数据,就能得到平均处理时间。
单缓冲常用的初始状态是:工作区满,缓冲区空。此时 CPU 可以处理工作区中的旧数据,设备可以向空缓冲区输入下一块数据。
对照 slides 分析:
- 若 $T>C$,设备输入更慢。CPU 处理完旧数据后,缓冲区还没有装满,不能把下一块数据传到工作区,只能等待设备输入结束。等输入结束后,再用 $M$ 把缓冲区内容传到工作区。此时又回到“工作区满,缓冲区空”的状态,所以一块数据平均耗时 $T+M$。
- 若 $T<C$,CPU 处理更慢。设备先把缓冲区装满,但单缓冲非空时不能继续输入下一块,只能等待 CPU 处理完旧数据。CPU 处理结束后,再用 $M$ 把缓冲区内容传到工作区。此时又回到“工作区满,缓冲区空”的状态,所以一块数据平均耗时 $C+M$。
因此,单缓冲处理一块数据的平均时间为:
$$
\max(C,T)+M
$$
双缓冲
双缓冲为 I/O 分配两个缓冲区。一个缓冲区供设备输入时,另一个缓冲区中的数据可以传送给用户工作区并被 CPU 处理。
双缓冲常取“工作区空,一个缓冲区满,另一个缓冲区空”作为初始状态。此时可以立刻把满缓冲区传到工作区,同时设备可以向另一个空缓冲区输入。
对照 slides 分析:
- 若 $T>C+M$,设备输入更慢。把已有满缓冲区传到工作区需要 $M$,CPU 处理需要 $C$,这两步合起来仍短于设备填满另一个缓冲区的时间。系统的节奏被设备输入限制,因此每处理一块数据平均耗时 $T$。
- 若 $T<C+M$,设备输入更快。设备较早填满空缓冲区,但用户工作区中的数据还没完成“传送 + 处理”,设备不能无限提前。系统的节奏被 $M+C$ 限制,因此每处理一块数据平均耗时 $C+M$。
因此,双缓冲处理一块数据的平均时间为:
$$
\max(T,C+M)
$$
单缓冲与双缓冲的区别:
| 项目 | 单缓冲 | 双缓冲 |
|---|---|---|
| 缓冲区数量 | 1 个 | 2 个 |
| 设备输入和 CPU 处理重叠 | 重叠能力弱 | 重叠能力更强 |
| 平均处理一块数据 | $\max(C,T)+M$ | $\max(T,C+M)$ |
| 通信方向 | 两台机器各一个单缓冲时,同一时刻通常只能单向传输 | 双缓冲可同时准备发送和接收,支持双向传输 |
循环缓冲
循环缓冲把多个大小相等的缓冲区组织成循环队列。
常见指针:
in:指向下一个可以装入数据的空缓冲区;out:指向下一个可以取出数据的满缓冲区。
循环缓冲适合连续输入或连续输出。生产者不断把数据放入空缓冲区,消费者不断从满缓冲区取数据。若空缓冲区耗尽,生产者等待;若满缓冲区耗尽,消费者等待。
缓冲池
缓冲池由系统中公用的多个缓冲区组成。操作系统按使用状态把缓冲区组织成队列。
三类队列:
| 队列 | 含义 |
|---|---|
| 空缓冲队列 | 可分配、可装入数据的空缓冲区 |
| 输入队列 | 已装满输入数据,等待进程提取的缓冲区 |
| 输出队列 | 已装满输出数据,等待设备输出的缓冲区 |
四种工作缓冲区:
| 工作缓冲区 | 作用 |
|---|---|
hin |
收容输入数据,从空缓冲队列取出,装满后挂到输入队列 |
sin |
提取输入数据,从输入队列取出,读空后挂回空缓冲队列 |
hout |
收容输出数据,从空缓冲队列取出,装满后挂到输出队列 |
sout |
提取输出数据,从输出队列取出,输出完后挂回空缓冲队列 |
SPOOLing
SPOOLing 是 Simultaneous Peripheral Operations On-Line,也叫假脱机技术。它用软件方式模拟脱机输入/输出,把慢速独占设备前面加上一层磁盘队列和管理进程。
SPOOLing 需要多道程序技术支持。系统中通常有输入进程、输出进程、输入井、输出井和内存缓冲区。
组成部分:
| 部分 | 位置 | 作用 |
|---|---|---|
| 输入井 | 磁盘 | 收容输入设备送来的数据 |
| 输出井 | 磁盘 | 收容用户进程要输出的数据 |
| 输入缓冲区 | 内存 | 暂存从输入设备到输入井的数据 |
| 输出缓冲区 | 内存 | 暂存从输出井到输出设备的数据 |
| 输入进程 | 系统进程 | 模拟脱机输入的外围控制机 |
| 输出进程 | 系统进程 | 模拟脱机输出的外围控制机 |
输入方向:
- 输入设备把数据送入内存输入缓冲区。
- 输入进程把缓冲区数据转存到磁盘输入井。
- 用户进程需要数据时,从输入井取得相应数据。
输出方向:
- 用户进程把要输出的数据提交给系统。
- 系统把输出数据放入磁盘输出井。
- 输出进程按队列取出输出任务,把数据经输出缓冲区送到输出设备。
共享打印机
普通打印机是独占设备:同一时刻只能真正打印一个任务。SPOOLing 可把它改造成逻辑上的共享设备。
多个进程请求打印时,系统并不把物理打印机直接分给每个进程,而是:
- 在输出井中为该进程申请一个磁盘存储区,保存待打印数据。
- 为该进程建立打印请求表,记录数据位置、打印参数等。
- 把打印请求表挂到假脱机文件队列。
- 打印机空闲时,输出进程从队列头取出一个请求。
- 输出进程把输出井中的数据送入输出缓冲区,再驱动打印机打印。
这样,每个用户进程都感觉自己提交了一个“独立打印机”的任务;物理上只有一台打印机,真正输出仍然按队列串行完成。
SPOOLing 不是让物理打印机真的并行打印多个任务,而是把独占设备前面的等待过程转移到磁盘队列中。它把一台物理独占设备虚拟成逻辑上的多台共享设备。
- 缓冲区用主存空间协调速度差异和传输单位差异。
- 单缓冲平均处理一块数据为 $\max(C,T)+M$。
- 双缓冲平均处理一块数据为 $\max(T,C+M)$。
- 循环缓冲适合连续生产、连续消费。
- 缓冲池通过空缓冲队列、输入队列、输出队列和四类工作缓冲区统一管理缓冲资源。
- SPOOLing 用磁盘输入井/输出井和系统进程模拟脱机 I/O,可把独占设备改造成虚拟共享设备。