Skip to content

入门:I/O 设备分类、控制方式与驱动

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

速查

  • I/O 管理的目标:让 CPU 与外设并行工作——外设慢(ms 级),CPU 快(ns 级),若 CPU 等外设将浪费百万倍时间,OS 用中断/DMA 让 CPU 在 I/O 期间做别的事。
  • 设备三大类:①块设备(磁盘/SSD/U 盘,按固定大小块寻址,可随机访问);②字符设备(键盘/鼠标/串口/打印机,按字节流访问,不可寻址);③网络设备(网卡,数据包收发,介于两者之间)。
  • 设备控制器:每个设备的硬件接口,有寄存器(状态/控制/数据)和设备缓冲,CPU 通过读写控制器寄存器操纵设备。
  • I/O 控制三方式(演进):①程序查询(轮询/忙等待)——CPU 反复查状态,全程占用,最浪费 CPU;②中断驱动——CPU 发命令后去做别的,设备完成发中断通知 CPU,CPU 利用率高但每字节一次中断(高频小数据开销大);③DMA(直接内存访问)——DMA 控制器接管,整块数据直接在设备与内存间传输,完成才发一次中断,CPU 几乎不参与
  • 设备驱动程序:OS 内核与具体硬件之间的适配层——把"读第 N 块"翻译成"对控制器写哪些寄存器",屏蔽硬件差异。Linux 把驱动抽象成 file_operations(open/read/write/ioctl)。
  • I/O 子系统分层:用户层 I/O 库(stdio)→ 系统调用(read/write)→ VFS/设备无关层设备驱动中断处理硬件
  • 缓冲(Buffering)目的:①缓解 CPU 与设备速度失配;②减少 I/O 次数(攒够一块再传);③协调块设备与字符设备的粒度差。分单缓冲、双缓冲、循环缓冲。
  • Spooling(假脱机):用磁盘 + 进程队列独占设备虚拟化成共享设备——典型:打印机。多个进程"同时"提交打印,实际在磁盘排队,逐个输出。
  • 磁盘访问三时间寻道时间(磁头移到柱面,主导)+ 旋转延迟(盘片转到扇区)+ 传输时间(读写扇区)。寻道最慢,所以调度算法优化寻道。
  • 磁盘调度算法:FCFS(先来先服务,公平但寻道长)、SSTF(最短寻道优先,可能饥饿)、SCAN(电梯算法,来回扫)、C-SCAN(只单向服务,返回不服务)、LOOK(到最远请求即返,不跑空)。
  • RAID:用多个廉价磁盘组成逻辑盘,条带化提速(并行)、镜像/校验容错。RAID 0(条带,无冗余)、RAID 1(镜像)、RAID 5(条带+分布式校验,主流)、RAID 10(1+0,镜像再条带)。
  • SSD vs 传统磁盘:SSD 无机械部件无寻道/旋转延迟,随机访问快百倍;但有写入寿命(NAND 擦写次数有限)和写放大,需磨损均衡与 TRIM。
  • 进阶顺序I/O 控制方式与缓冲磁盘调度与 RAID参考

一、I/O 设备的分类

外设五花八门,OS 按信息传输单位寻址方式把它们分三类:

  1. 块设备(Block Device):以固定大小的块为单位传输(磁盘一块 512B/4KB),支持寻址(能直接读写第 N 块),可随机访问。代表:磁盘、SSD、U 盘、光盘。文件系统建立在块设备之上。
  2. 字符设备(Character Device):以字节流为单位传输,不可寻址(只能顺序读,不能跳到第 N 字节),通常只能顺序访问。代表:键盘、鼠标、串口、终端、打印机。Linux 里 /dev/tty/dev/null 都是字符设备。
  3. 网络设备(Network Device):传输数据包(packet/frame),介于块与字符之间,有收发队列。Linux 里它不是 /dev 下的文件,而是通过 socket 接口访问。
  • 共享 vs 独占:磁盘/网卡是共享设备(多进程可并发分时使用);打印机、磁带机是独占设备(一次只能给一个进程用,否则混乱)——独占设备靠 Spooling 虚拟化成共享。
  • 设备 → 控制器 → 总线:设备通过设备控制器(Controller)接总线,控制器有状态寄存器(设备忙/闲/错)、控制寄存器(启动/方向/块号)、数据寄存器(缓冲)。CPU 对设备的操作 = 对控制器寄存器的读写。

二、I/O 控制三方式:从忙等待到 DMA

CPU 怎么和设备交换数据?三种方式,越往后 CPU 占用越少

1. 程序查询(轮询 / 忙等待)

CPU 发出 I/O 命令后,反复读状态寄存器判断设备是否完成:

CPU: while (状态寄存器 == 忙) ;   // 死循环轮询,CPU 全程占用
CPU: 读数据寄存器                // 完成后取数据
  • 致命缺点CPU 全程忙等待,浪费百万倍时间(设备 ms 级,CPU ns 级)。期间 CPU 无法执行其他进程。
  • 仅用于极简单/早期系统或嵌入式特定场景。现代 OS 几乎不用。

2. 中断驱动

CPU 发出 I/O 命令后立即去做别的(执行其他进程或切换),设备完成后发中断信号,CPU 响应中断执行中断处理程序取数据:

CPU: 写控制寄存器(启动设备)→ CPU 去执行别的进程
设备: 完成 → 发中断
CPU: 响应中断 → 跳到中断处理程序 → 读数据寄存器 → 唤醒等待进程
  • 优点:CPU 与设备并行,CPU 利用率大增。
  • 缺点每传一个单位(如 1 字节/1 字)就发一次中断,高频小数据时中断开销淹没 CPU(上下文切换太频繁)。

3. DMA(直接内存访问 Direct Memory Access)

为解决中断驱动的高频中断问题,引入 DMA 控制器(DMAC):CPU 把整块传输任务(源、目的、长度)交给 DMAC,DMAC 与设备、内存直接打交道,整个块传完才发一次中断

CPU: 设置 DMAC(源=设备,目的=内存地址,长度=N)→ CPU 去执行别的
DMAC: 接管总线,逐字节/字在设备↔内存间搬运,CPU 不参与
DMAC: 全部传完 → 发一次中断通知 CPU
  • 优点大批量数据 CPU 几乎零干预,只在开始(设置)和结束(一次中断)参与。用于磁盘、网卡等大数据块传输。
  • 关键:DMA 期间周期窃取(cycle stealing)——DMAC 周期性占用总线一个周期传一字,CPU 稍有停顿但远好于中断驱动。
  • 进阶:通道(Channel):大型机更进一步,通道是可编程的 I/O 处理器,能执行通道程序,独立完成复杂 I/O 任务,CPU 只管启动与收尾。

三方式对比

方式CPU 参与度中断频率数据单位适用
程序查询全程忙等待字/字节极简单/嵌入式
中断驱动每单位参与每单位一次字/字节慢速字符设备(键盘)
DMA仅起止参与整块一次块设备(磁盘/网卡)

三、设备驱动程序

设备驱动(Device Driver)是 OS 内核与具体硬件之间的适配层/翻译层。OS 上层(VFS、系统调用)是设备无关的,它只说"读第 N 块";具体怎么"读"(对哪个控制器的哪个寄存器写什么值)由驱动完成:

  • 屏蔽硬件差异:同样是"读磁盘块",SCSI 盘、SATA 盘、NVMe 盘的控制器指令完全不同,但驱动把它们都翻译成统一的 read 接口。OS 之所以能支持海量设备,靠的就是驱动分层
  • 运行位置:传统上驱动在内核态(Linux LKM、Windows .sys),驱动 bug 会崩内核。现代趋势是部分驱动放用户态(如 Linux 的 FUSE 文件系统、Windows 的 UMDF)以提升可靠性。
  • Linux 的驱动抽象:把所有设备抽象成文件,驱动实现 file_operations 结构体(open/read/write/ioctl/close),应用用统一 read(fd, buf, n) 访问任何设备。
  • 驱动是内核崩溃的头号元凶:因为驱动多(数千个)、来自各厂商、质量参差,且运行在内核态——Linux/Windows 蓝屏/panic 多数由驱动 bug 引发。这正是微内核想把驱动移用户态的动机。

下一步

理解了 I/O 设备分类、三方式演进与驱动角色后,下一步深入I/O 控制方式与缓冲(忙等待/中断/DMA 的工程取舍、缓冲如何缓解速度失配、Spooling 如何虚拟化独占设备),以及磁盘调度与 RAID(如何优化磁盘访问、如何用冗余保证可靠)。