Skip to content

I/O 控制方式与缓冲

基于通用操作系统概念 · 核于 2026-08

速查

  • I/O 控制演进:程序查询(忙等待,CPU 全占)→ 中断驱动(CPU 起止参与,每单位一中断)→ DMA(整块传完才一中断,CPU 几乎零干预)→ 通道(可编程 I/O 处理器)。
  • 程序查询:CPU while(忙) 死循环轮询状态寄存器——最浪费 CPU,现代 OS 不用。
  • 中断驱动:CPU 发命令即返回,设备完成发中断,CPU 响应取数据——CPU 与设备并行,但每字节一中断,高频小数据开销大。
  • DMA:CPU 把整块任务交给 DMA 控制器(DMAC),DMAC 直接在设备↔内存间搬运(周期窃取总线),整块完成才发一次中断——用于磁盘/网卡等大数据块。
  • DMA 三要素:CPU 给 DMAC 设 源地址(设备/内存)、目的地址(内存/设备)、传输长度,DMAC 自主完成。
  • 缓冲(Buffering):在内存开缓冲区暂存 I/O 数据,目的:①缓解 CPU 与设备速度失配;②减少 I/O 次数(攒够一块);③协调块设备与字符设备的粒度差。
  • 单缓冲:设备→缓冲区→用户区,CPU 与设备可部分并行,但任一时刻只一方用缓冲
  • 双缓冲:两块缓冲交替——设备填 A 时 CPU 取 B,A 满换 B 填——CPU 与设备并行度更高,适合持续流式 I/O。
  • 循环缓冲:多个缓冲组成环形队列,进一步平滑突发 I/O,常用于生产者-消费者(网卡收包)。
  • 缓冲 vs 缓存(Cache):缓冲目的是减少 I/O 次数/速度匹配(必经缓冲);缓存目的是复用最近数据(命中即不读设备),如页缓存。
  • Spooling(假脱机,Simultaneous Peripheral Operations On-Line):用磁盘 + 队列独占设备虚拟化成共享设备——多进程"同时"提交打印,实际排队在磁盘,逐个输出。代表:打印机、邮件发送。
  • Spooling 三要素:①高速磁盘(虚设备载体);②输入/输出井(磁盘上的排队区);③Spooling 守护进程(管理队列、调度实际输出)。
  • 设备分配:独占设备需分配(避免冲突)——按设备类(多道)/物理设备(单道)/通道分层分配,配 DCT/COCT/CHCT 等数据结构(考研)。

一、程序查询:最原始的忙等待

程序查询(Programmed I/O,轮询):CPU 主动、反复地读设备状态寄存器,直到设备"就绪"再读/写数据寄存器:

发命令(写控制寄存器):
  loop:
    if (状态寄存器 == 忙) goto loop   // 死循环,CPU 全占用
  数据 = 数据寄存器                   // 就绪,取数据
  • 致命缺点CPU 全程忙等待。设备完成一次 I/O 通常要 ms 级(磁盘寻道+旋转),而 CPU 一条指令只要 ns 级——CPU 在 while(忙) 里空转百万条指令,100% 浪费
  • 期间 CPU 无法执行其他进程(即便在多道系统,轮询也独占 CPU),吞吐极低
  • 仅用于:极简单的嵌入式系统、或设备必定"立即就绪"的场景(如读内存映射寄存器)。现代通用 OS 不用

二、中断驱动:CPU 与设备并行

中断驱动 I/O:CPU 发出命令后立即返回去执行别的进程;设备完成传输后发硬件中断,CPU 响应中断、执行中断处理程序取走数据:

CPU: 写控制寄存器(启动设备) → 进程阻塞,调度别的进程执行
设备: 传输完成 → 拉高中断信号线
CPU: 当前指令结束 → 响应中断 → 保存现场 → 跳中断处理程序
       → 中断处理: 数据 = 数据寄存器 → 唤醒等 I/O 的进程 → 恢复现场
  • 优点CPU 与设备并行工作——I/O 期间 CPU 跑别的进程,利用率大增。这是现代 OS 的基础。
  • 缺点(高频小数据):每传一个单位(字节/字)就发一次中断。传 1KB 数据要 1024 次中断,每次中断都有上下文切换开销(μs 级),中断处理时间可能超过数据传输本身,CPU 被中断淹没。
  • 缓解:配合缓冲——攒够一块再传,减少中断次数;或升级到 DMA。

三、DMA:大批量数据零干预

DMA(Direct Memory Access,直接内存访问):为消除中断驱动的高频中断,引入专门的 DMA 控制器(DMAC)。CPU 把整块数据传输任务交给 DMAC,DMAC 直接在设备与内存之间搬运数据,不需要 CPU 逐字节参与,整块传完才发一次中断:

CPU: 向 DMAC 写入——源(设备)、目的(内存地址)、长度(N) → 启动 → CPU 去执行别的进程
DMAC: 接管总线,逐字节/字在设备↔内存搬运
       (总线冲突时用"周期窃取"——DMAC 借一个总线周期传一字,CPU 稍停顿)
DMAC: N 字节传完 → 发一次中断通知 CPU
CPU: 响应中断 → 收尾(唤醒进程)
  • 核心优势大批量数据 CPU 几乎零干预。CPU 只在开始(设置 DMAC)和结束(一次中断)参与,中间传几 KB/M 数据 CPU 全程不介入。
  • 总线控制:DMA 期间 DMAC 成为主总线控制者,与 CPU 分时共享总线——当 DMAC 和 CPU 同时要总线,DMAC 用周期窃取(cycle stealing)突发模式(burst)
  • 适用块设备(磁盘、SSD、网卡)的大数据块传输。这是现代磁盘 I/O 的标配。
  • 与中断驱动对比:同样传 4KB——中断驱动要 4096 次中断,DMA 只要 1 次
  • 进阶:通道(Channel):大型机(IBM S/390)用通道——比 DMAC 更强,是可编程的 I/O 处理器,能执行通道程序(一组 I/O 指令链),独立完成复杂的 I/O 序列,CPU 只管启动和收尾。通道是 DMA 的"超集"。

DMA vs 中断 vs 程序查询

维度程序查询中断驱动DMA
CPU 参与全程忙等待每单位参与仅起止参与
中断频率每单位一次整块一次
传输单位字/字节字/字节
CPU 利用率极低最高
数据通路设备↔CPU↔内存设备↔CPU↔内存设备↔内存(绕过 CPU)
适用极简单慢速字符设备块设备大批量

四、缓冲:缓解速度失配

缓冲(Buffering):在内存开辟缓冲区暂存 I/O 数据。三个目的:①缓解 CPU 与设备速度失配(CPU 快、设备慢,缓冲做"蓄水池");②减少 I/O 次数(攒够一块再传,比逐字节高效);③协调块设备与字符设备的粒度差

  1. 单缓冲(Single Buffer):OS 在内核设一块缓冲区。设备把数据填入缓冲区,CPU 从缓冲区取——任一时刻只有一方能用缓冲(互斥),但"设备填下一块"与"CPU 处理上一块"可部分并行。每块处理时间 ≈ max(设备填, CPU 处理)。
  2. 双缓冲(Double Buffer):设两块缓冲区 A、B 交替使用。设备填 A 时,CPU 同时从 B 取;A 满后切换——设备填 B、CPU 取 A。CPU 与设备并行度显著提升,适合连续流式 I/O(音视频、串口)。
  3. 循环缓冲(Circular Buffer)多个缓冲区组成环形队列,一个生产者写、一个消费者读,用头尾指针管理。进一步平滑突发 I/O,常用于网卡收包、管道、生产者-消费者。
  • 缓冲 vs 缓存(Cache):容易混淆。缓冲目的是"减少 I/O 次数 + 速度匹配"——数据必经缓冲(如磁盘块先读进内核缓冲区再给用户)。缓存目的是"复用最近用过的数据"——命中就直接用、不再读设备(如 Linux 的 page cache,第二次读同一文件从内存直接取)。
  • 代价:缓冲占用额外内存,且数据常需在"用户缓冲↔内核缓冲↔设备"间多次拷贝(双倍拷贝问题,sendfile/mmap/io_uring 旨在减少拷贝)。

五、Spooling:独占设备虚拟化

Spooling(Simultaneous Peripheral Operations On-Line,外部设备同时联机操作 / 假脱机):用高速磁盘 + 队列独占设备改造成共享设备的技术。

  • 问题背景:打印机是独占设备——一次只能服务一个进程。若进程 A 打印 100 页,进程 B 要等很久;且若 A 打印到一半崩溃,打印机就卡死。直接共享会冲突/混乱
  • Spooling 做法:所有进程的打印任务不直接发给打印机,而是先写到磁盘上的"输出井"(一个排队目录),每个任务排成队列。一个 Spooling 守护进程(打印后台)按队列顺序,一个一个取出送往实际打印机。
  • 效果:每个进程"提交即返回"(瞬间完成,因为只是写磁盘),感觉自己在独占打印机——独占设备被虚拟化成了多进程共享的设备。
  • 三要素:①高速磁盘(虚拟设备的载体,开输入井/输出井);②输入井/输出井(磁盘上的排队区);③Spooling 守护进程/后台(管理队列、调度实际设备输出)。
  • 典型应用:打印机(lpr/lpd)、邮件发送队列、批处理作业的输入井。
  • 本质:用空间换时间 + 异步——用磁盘空间缓冲,把"独占设备串行访问"转成"磁盘多进程并发写 + 设备串行输出"。

下一步

I/O 控制与缓冲讲完后,下一个核心是磁盘调度与 RAID——磁盘的物理结构如何决定访问时间、FCFS/SSTF/SCAN/C-SCAN/LOOK 算法如何优化寻道、RAID 0/1/5/10 如何兼顾性能与可靠。