编程与 AI14 分钟阅读更新于 2026-08-04

设备 I/O 怎么和 CPU 协作:控制器、中断与键盘输入

解释 CPU 如何通过设备控制器发出 I/O 指令,以及设备完成工作后如何通过中断通知处理器,并以键盘输入说明数据进入系统的过程。

相关工具

外设为什么不能直接和程序对话

键盘、磁盘、显示器和网卡的工作方式各不相同。程序如果直接面对每种设备的电气信号、时序和寄存器,就必须为每一类硬件编写完全不同的逻辑,应用也会被某一种设备牢牢绑定。

操作系统在程序和设备之间安排了控制器与驱动。程序提出较抽象的请求,驱动把请求转换成设备控制器能够理解的操作;设备完成工作后,再把状态和数据交回系统。这样,硬件差异被压在较低层,应用可以使用相对统一的输入输出方式。

应用、操作系统驱动、设备控制器和外设之间的 I/O 分层结构图
程序与设备之间的 I/O 分层

应用提出请求,驱动和控制器负责转换,外设完成实际工作并返回状态。

设备控制器承担了什么工作

设备控制器是处理器和外设之间的中间部件。它通常包含控制寄存器、状态寄存器和数据缓冲区,处理器通过规定好的读写方式下达命令、查看设备状态或交换数据。控制器还可能负责把设备产生的信号整理成处理器可以处理的状态。

以输出为例,程序把要显示或写出的内容交给系统,驱动再把它转换成控制器需要的格式。控制器开始驱动设备后,处理器不必一直盯着设备的每一个细节,只要在需要时查询状态,或者等待设备主动通知完成。

一次设备 I/O 的基本流程

一次 I/O 通常从处理器发出控制命令开始。驱动把命令写入控制器的寄存器,准备好数据缓冲区,并让设备开始工作。设备执行期间,处理器可以继续处理其他任务,不必把全部时间消耗在等待外设转动、移动或响应上。

设备完成操作后,会更新状态并发出通知。系统进入相应的处理流程,检查这次操作是否成功,取走输入数据或确认输出结果,再唤醒等待中的程序。若操作失败,系统还要把错误状态转换成上层能够理解的结果。

CPU、设备控制器和外设通过命令、执行和中断形成闭环的流程图
设备 I/O 的完整闭环

CPU 发出命令,控制器启动外设,外设完成后通过中断通知系统,系统再交付结果。

为什么需要中断

最简单的等待方式是轮询:处理器不断读取设备状态,反复询问“完成了吗”。轮询实现直观,但设备工作时间较长时,处理器会把大量时间花在重复检查上;如果轮询间隔太短,浪费计算资源,间隔太长,又可能增加响应延迟。

中断把通知主动权交给设备。处理器发出请求后可以继续运行,设备完成或发生异常时向处理器发出中断信号。处理器暂时保存当前执行现场,转入中断处理流程,处理完设备事件后再回到原来的工作。这样,等待期间的处理器时间可以被其他任务利用。

中断处理不会凭空改变程序状态

中断到来时,处理器需要保存足够的现场信息,例如当前指令位置和部分寄存器状态,确保处理结束后能够继续原来的执行路径。系统随后根据中断来源找到对应的处理程序,读取设备状态并完成必要的数据搬运。

中断处理程序通常只做紧急而明确的工作,例如确认设备、取走数据、记录状态和唤醒后续处理。较复杂的解析和业务逻辑可以交给稍后运行的任务完成。这样既能尽快响应新的中断,也能避免在中断上下文中停留太久。

键盘输入是怎样进入程序的

按下键盘按键后,键盘控制器会产生表示按键动作的扫描码。设备通过中断通知处理器,系统的中断处理流程读取扫描码,并把它转换为更适合上层使用的键盘事件。按键释放也可能产生对应事件,因此程序才能区分按下、持续和松开等状态。

转换后的输入不会一定直接交给当前程序,而通常会先进入输入缓冲队列。上层程序按照自己的节奏读取队列中的字符或事件。这样,键盘输入不会因为程序暂时忙碌而立即丢失,也能让终端、图形界面和其他输入消费者拥有不同的处理方式。

键盘扫描码经过控制器、中断处理和输入缓冲队列进入应用的流程图
键盘输入进入程序的路径

键盘产生扫描码,控制器发出中断,系统转换并放入缓冲队列,程序再读取输入事件。

中断和 I/O 多路复用如何衔接

中断解决的是设备如何通知内核,I/O 多路复用解决的是应用如何等待多个文件描述符。设备中断到来后,内核更新套接字、管道或设备文件对应的状态;当这些对象满足可读或可写条件时,等待中的 select、poll 或 epoll 才能返回。

因此,应用通常不需要直接处理硬件中断。它通过统一的文件描述符接口等待事件,内核在更底层完成中断接收、状态更新和唤醒。两套机制处在不同层次:一个连接硬件和内核,一个连接内核和应用。

为什么输入输出需要缓冲区

外设和处理器的速度、数据粒度经常不一致。键盘一次产生一个小事件,磁盘一次传输一个块,网卡可能连续收到很多数据。如果每个字节都立即触发完整的软件处理,系统会被大量细小操作打断。

缓冲区把生产者和消费者暂时隔开。设备先把数据放入缓冲区,系统按合适的批量取走;程序如果暂时没有读取,数据也可以在队列中等待。缓冲区不是无限的,队列满时可能丢弃新数据、阻塞生产者或触发流量控制,所以系统还需要定义满和空的处理规则。

用一条主线理解设备 I/O

应用提出请求,驱动把请求翻译成控制器命令,控制器启动外设,外设完成工作后更新状态并触发中断。内核在中断处理过程中读取数据、记录结果、更新缓冲区,再唤醒等待中的程序。

遇到“输入为什么没有到达程序”这类问题时,可以沿着这条链逐层检查:设备是否产生信号,控制器是否收到命令,中断是否到达,数据是否进入缓冲区,文件描述符是否变为就绪,以及应用是否正确读取。这样可以把硬件事件、内核状态和应用行为区分开。

常见问题

中断和轮询有什么区别?

轮询由处理器反复检查设备状态,中断则由设备在完成或异常时主动通知处理器。轮询简单但可能浪费 CPU,中断更适合等待时间不确定的设备。

键盘中断处理程序会直接执行应用逻辑吗?

通常不会。它主要读取扫描码、更新输入状态和缓冲队列,应用随后通过终端或图形输入接口读取转换后的事件。

设备控制器为什么需要状态寄存器?

状态寄存器用于表示设备是否忙、是否完成、是否出错以及是否有数据可取,处理器和驱动可以据此决定下一步动作。