Appearance
缓冲区管理
2026 大纲 五(二)1 缓冲区管理,属「设备独立软件」层。
一个每秒几十字节,一个每秒几十亿次
前面几节把设备的"杂"处理完了:控制器统一了形态、分层统一了调用、 驱动吃掉了差异、分配决定了给谁。只剩最后一件事没解决——慢。
I/O 控制方式确实让 CPU 不用干等了(中断、DMA), 但它只解决了"等的时候能不能干别的",没解决另外三处不匹配:
速度不匹配——键盘每秒吐几十个字符,CPU 每秒能处理几十亿次。 没有中间存放处,字符一来就得立刻有人接,接慢一点就丢了。
粒度不匹配——磁盘按块读写(一次 512 B 或 4 KB),而程序可能只想读 3 个字节。 没有中间存放处,读 3 个字节也得占着整整一块的传输时间。
时机不匹配——进程想写的时候设备也许正忙,设备准备好的时候进程也许还没读。
这三处都靠同一样东西化解:在中间放一块内存,叫缓冲区。 ⚠️ 要注意速度不匹配与粒度不匹配是两件独立的事—— 即使两边速度一样,粒度不同照样需要缓冲。
这一节的技术内容集中在算时间:单缓冲、双缓冲各花多久,这是本章唯一的计算题型。 两个公式看着差不多,但差别只在一处很具体的地方——
一、引入缓冲的四个目的
四个目的不是并列的四条,而是同一个矛盾的四个侧面:生产者(设备或 CPU)与消费者(CPU 或设备)在速度、粒度、时机三方面对不上。
| 目的 | 具体矛盾 | 缓冲区怎么化解 |
|---|---|---|
| 缓和速度不匹配 | CPU 速度远快于设备 | 生产者不必等消费者就绪就能把数据放下 |
| 减少中断频率、放宽响应时限 | 每来一个字符中断一次,CPU 被打断得太频繁 | 攒够一批再中断一次 |
| 解决粒度不匹配 | 设备按块吐、应用按记录取,或反过来 | 一次产出可供分几次取,或攒几次凑成一次 |
| 提高并行性 | 没缓冲时双方必须"面对面交接",谁先到谁等 | 交接变异步:放下就走,取走就用 |
二、单缓冲与双缓冲
单缓冲:内存中设一个缓冲区。设备把一块数据传入缓冲区(
三段时间各自占用了什么资源,就是公式的全部成因:
双缓冲(又称缓冲对换):设两个缓冲区,设备装满 A 就转去装 B,OS 同时把 A 里的数据搬到工作区。关键变化是
单缓冲与双缓冲的逐拍时间表:谁占着缓冲区、周期从哪读出来(想看清搬出数据那段时间怎么挡住设备时展开)
取一组具体的数:
单缓冲,连续三块:
| 时刻 (ms) | 缓冲区在做什么 | 用户工作区在做什么 |
|---|---|---|
| 0 – 8 | 第 1 块的 | 空 |
| 8 – 9 | 第 1 块的 | 第 1 块的 |
| 9 – 14 | 第 2 块的 | 第 1 块的 |
| 14 – 17 | 第 2 块的 | 空( |
| 17 – 18 | 第 2 块的 | 第 2 块的 |
| 18 – 23 | 第 3 块的 | 第 2 块的 |
| 23 – 26 | 第 3 块的 | 空 |
| 26 – 27 | 第 3 块的 | 第 3 块的 |
周期怎么读出来:看同一事件反复出现的间隔——第 1 块的
双缓冲,同一组数,A、B 轮流用:
| 时刻 (ms) | 缓冲区 A | 缓冲区 B | 用户工作区 |
|---|---|---|---|
| 0 – 8 | 第 1 块的 | 空 | 空 |
| 8 – 9 | 第 1 块的 | 第 2 块的 | 第 1 块的 |
| 9 – 14 | 空 | 第 2 块的 | 第 1 块的 |
| 14 – 16 | 空 | 第 2 块的 | 空(CPU 侧只要 6 ms,先干完了) |
| 16 – 17 | 第 3 块的 | 第 2 块的 | 第 2 块的 |
| 17 – 22 | 第 3 块的 | 空 | 第 2 块的 |
| 22 – 24 | 第 3 块的 | 空 | 空 |
周期:第 1 块的
把这组数推到 10 块,三种配置的总耗时:
| 配置 | 每块耗时 | 处理 10 块 |
|---|---|---|
| 单缓冲 | 90 ms | |
| 双缓冲 | 80 ms | |
| 8 个缓冲区的循环缓冲 | 仍是 | 80 ms,与双缓冲完全相同 |
三行各自的算法不同:单缓冲先比
换一组参数即可看出双缓冲也不总占优:
三、缓冲区数量 → 每块耗时的一般模型
单缓冲、双缓冲只是
| 缓冲区数 | 每块平均耗时 | 为什么 |
|---|---|---|
| 只有一个缓冲区, | ||
| 设备写另一个缓冲区, | ||
| 仍是 | 稳态吞吐由较慢那一级决定,加缓冲区不能让慢的那级变快 |
加缓冲区改善的是平滑度,不是稳态平均值
若
多设缓冲区图的是抗突发:设备速率或 CPU 处理速率不稳定时,多缓冲区吸收波动,不让瞬时的慢拖住对方。教材的说法是——"当输入与输出的速度基本相匹配时双缓冲效果就够好,若两者相差甚远,可随着缓冲区数量的增加使情况有所改善"。改善的是平滑度。
四、循环缓冲(环形缓冲区)
把多个大小相同的缓冲区组织成环形队列,输入进程与计算进程各在环上追赶。
| 缓冲区类型 | 含义 | 对应指针 | 指针指向 |
|---|---|---|---|
| R(空缓冲区) | 可供输入进程装数据 | Nexti | 输入进程下次可用的空缓冲区 R |
| G(已装满数据) | 等待计算进程取用 | Nextg | 计算进程下一个可用的缓冲区 G |
| C(现行工作缓冲区) | 计算进程正在使用 | Current | 该缓冲区中正在处理的单元 |
- Getbuf:计算进程调用时,把 Nextg 指的缓冲区交给它、改为现行工作缓冲区 C,Current 指向其第一个单元,Nextg 前移一格;输入进程调用时,把 Nexti 指的空缓冲区交给它,Nexti 前移一格。
- Releasebuf:计算进程取完数据后调用,把 C 改回空缓冲区 R;输入进程装满后调用,把该缓冲区改为 G。
两个指针沿同一方向移动,会出现两种"撞车":
| 情形 | 含义 | 谁阻塞 | 谁唤醒它 | 教材叫法 |
|---|---|---|---|---|
| Nexti 追上 Nextg | 输入快于计算,空缓冲区用光 | 输入进程阻塞 | 计算进程 Releasebuf 释放出空缓冲区时 | 系统受计算限制 |
| Nextg 追上 Nexti | 计算快于输入,装满的缓冲区被抽空 | 计算进程阻塞 | 输入进程装满某块调 Releasebuf 时 | 系统受 I/O 限制 |
五、缓冲池
专用缓冲是为特定的一对生产者/消费者设的,系统一大就要开很多套,内存耗得多、利用率还低。于是引入既可输入又可输出的公用缓冲池。
每个缓冲区由缓冲首部(缓冲区号、设备号、数据块号、同步信号量、队列链接指针)与缓冲体(存数据)组成。同类型的缓冲区链成队列,共三个;另有四种工作缓冲区:
| 操作(工作缓冲区) | 从哪个队列取 | 用完挂到哪个队列 |
|---|---|---|
| 收容输入 | 空白缓冲队列 emq → 装入输入数据 | 输入队列 inq |
| 提取输入 | 输入队列 inq → CPU 取走处理 | 空白缓冲队列 emq |
| 收容输出 | 空白缓冲队列 emq → 装入输出数据 | 输出队列 outq |
| 提取输出 | 输出队列 outq → 送往设备 | 空白缓冲队列 emq |
数据结构里的 Addbuf(挂队尾)、Takebuf(摘队首)不能直接用:缓冲池里的队列本身是临界资源,多个进程会同时访问同一队列。为每个队列加互斥信号量
六、磁盘高速缓存与两级缓冲区
磁盘高速缓存指利用内存中的存储空间暂存从磁盘读出的数据;它不是 CPU 与主存之间的硬件 Cache,而是操作系统在内存里维护的磁盘数据副本。两种组织形式:
| 形式 | 说明 |
|---|---|
| 固定专用缓存区 | 在内存中开辟固定大小的区域,专门缓存磁盘数据 |
| 动态缓冲池 | 利用系统空闲内存作缓冲池,供请求分页与磁盘 I/O 共享 |
用户缓冲区是用户进程自己申请的一块内存(如一个数组),每次 read 把数据填进去,处理完再发下一次 read——省的是系统调用次数。内核缓冲区由 OS 在内核空间维护:读命中就直接复制到用户缓冲区,未命中才发起磁盘 I/O 并挂起进程;写操作先落内核缓冲区,攒够一定量或满足刷新条件才批量写盘——省的是实际磁盘 I/O 次数。
考点速记
- 缓冲区化解的是速度、粒度、时机三方面的不匹配。⚠️速度不匹配与粒度不匹配是两件独立的事——即使两边速度一样,粒度不同照样需要缓冲。
- 符号口径:
是设备把一块数据送进缓冲区的时间, 是缓冲区到用户工作区的传送时间, 是 CPU 处理一块的时间。 - 单缓冲:每块平均耗时
。 理由是 期间缓冲区被占着,设备不能往里送下一块,所以 必须单独加。 - 双缓冲:每块平均耗时
。 理由是有第二个缓冲区, 期间设备可以往另一个里送,所以 被并进 CPU 那一侧。 - ⚠️两个公式唯一的差别就是
期间挡不挡得住设备——记住这一句,公式不用背。 起公式不再变化,多缓冲区买的是抗波动而非更高吞吐。 - 缓冲池的队列是临界资源,
Getbuf必须先(资源信号量)后 (互斥信号量),顺序反了会死锁。 - 磁盘高速缓存与缓冲区的分界是"数据取走后还留不留":缓冲区取走即空出、留给下一批;磁盘高速缓存取走后仍留着,指望下次还命中。
- ⚠️设置磁盘缓冲区的主要目的是减少磁盘 I/O 次数——不是减少平均寻道时间(那是磁盘调度的事)、不是提高数据可靠性、也不是实现设备无关性(那是 LUT 的事)。
- 能改善磁盘 I/O 性能的手段:重排 I/O 请求次序(磁盘调度)、预读与滞后写(缓冲)、优化文件物理块的分布(减少寻道)。⚠️在一个磁盘上设置多个分区不能改善性能——分区只是逻辑划分,反而可能让访问跨区、寻道更远。
这一节在真题里被考过的形式:
三道题:两道算时间,一道问缓冲的目的。 计算那一类是本章唯一的题型,必须练熟。
- 给
、 、 与块数,算单缓冲与双缓冲下读入并处理完的总时间(2011-31)。10 块,答单缓冲 1550 μs、双缓冲 1100 μs。⚠️ 两处容易错:最后一块要单独算(前 块按稳态公式走,最后一块还要加上它自己的 ,不能直接乘 );以及别把两个公式记混——差别只在 那一项的位置(速记第五条)。 - 系统缓冲区与用户工作区均单缓冲,问读入并分析 2 个数据块的最短时间(2013-27)。这道题把两级缓冲串起来了,要按流水线排时间线,不能直接套单块公式乘 2。判据仍是速记第三条——每一级的
期间,它上游的那一级都被挡住了。 - 问在系统内存中设置磁盘缓冲区的主要目的(2015-28)。答减少磁盘 I/O 次数。⚠️ 另三项各自属于别的机制:减少平均寻道时间是磁盘调度算法干的、提高数据可靠性靠的是冗余与校验、实现设备无关性靠的是逻辑设备表。
- 问哪一项不能改善磁盘设备的 I/O 性能(2012-32,与磁盘结构与调度共享)。答在一个磁盘上设置多个分区。⚠️ 分区是逻辑划分,不改变任何物理特性;反而可能因为数据被分到不同分区而让磁头跑得更远。另三项都能:重排 I/O 请求次序、预读和滞后写、优化文件物理块的分布。
复习优先级:必须拿满,且计算要练熟。 速记第三到五条是全部计算题的依据, 把"
易错:把单缓冲和双缓冲的公式记混。差别只在
期间设备能不能继续送——不能就单独加,能就并进 CPU 侧。
易错:算总时间时直接用公式乘块数。最后一块要单独加上它的
。
易错:认为缓冲区数量越多吞吐越高。
起公式就不变了,多的缓冲区买的是抗波动。
易错:认为设置磁盘缓冲区是为了减少寻道时间。目的是减少磁盘 I/O 次数;减少寻道是磁盘调度的事。
易错:认为在一个磁盘上分多个区能提升 I/O 性能。分区是逻辑划分,不改变物理特性。
易错:把磁盘高速缓存和缓冲区当成一回事。分界是数据取走后还留不留。
易错:认为速度匹配了就不需要缓冲。粒度不匹配是独立的一件事。
教材出处
- 引入缓冲的四个目的、单缓冲区每块处理时间
的推导与字符设备的行缓冲约定:汤小丹《计算机操作系统》6.7.1~6.7.2 节,印刷 p210 - 双缓冲区(缓冲对换)与"粗略地认为是
"的口径、双机通信时的缓冲区设置:同书 6.7.2 节,印刷 p211 - 环形缓冲区的三类缓冲区 R/G/C、三个指针 Nextg/Nexti/Current、Getbuf 与 Releasebuf 过程、两个指针互相追赶导致的两种阻塞:同书 6.7.3 节,印刷 p212
- 缓冲池的组成(缓冲首部与缓冲体、emq/inq/outq 三队列、四种工作缓冲区)与 Getbuf/Putbuf 中互斥信号量 MS 和资源信号量 RS 的设置:同书 6.7.4 节,印刷 p213
相关知识
I/O 控制方式|I/O 软件层次结构|设备分配与回收|磁盘结构与调度