跳转至

I_O焕新重制版

年份 考点 分值
2009 磁盘调度算法(\(SCAN\)调度)、设备分配与回收、中断方式传送、\(DMA\)传送 2*2+8=\(12\)分
2010 中断处理程序  应用题:磁盘调度策略、磁盘空闲块管理、磁盘读写时间 2+7=\(9\)分
2011 程序查询\(I/O\)控制方式、中断处理程序、设备驱动程序、用户程序、缓冲区管理 2*2=\(4\)分
2012 \(I/O\)接口(数据线)、\(I/O\)子系统、磁盘\(I/O\)性能 2*3=\(6\)分
2013 磁盘阵列(\(RAID\))、磁盘读取时间、中断\(I/O\)方式与\(DMA\)方式对比、设备驱动程序、缓冲区管理 5*2=\(10\)分
2014 \(I/O\)接口、\(I/O\)端口及其编址、程序控制中断方式耗时 2*2=\(4\)分
2015 \(I/O\)接口、缓冲区管理、磁盘调度算法(\(SCAN\)调度) 2*3=\(6\)分
2016 假脱机(\(SPOOLing\))技术 \(2\)分
2017 簇、磁盘逻辑格式化、\(DMA\)传送 2*3=\(6\)分
2018 磁盘调度算法 2分
2019 磁盘的组成等基本信息、中断方式时间开销、\(DMA\)传送、大题:设备驱动程序、磁盘调度算法、磁盘容量计算 6+7=\(13\)分
2020 \(DMA\)传送、设备分配与回收 2*2=\(4\)分
2021 磁盘调度算法(\(SSTF\))、磁盘的管理(操作系统引导、磁盘引导) 2+8=\(10\)分
2022 中断\(I/O\)方式、设备驱动程序、大题:磁盘地址划分、扇区平均访问时间、\(DMA\)传送 4+8=\(12\)分
2023 \(I/O\)控制方式、设备分配管理  应用题:键盘输入字符过程分析(设备驱动程序、中断处理等) 4+8=\(12\)分

【考纲内容】

  1. I/O 管理基础

(1) 设备:设备的基本概念;设备的分类;I/O 接口;I/O 端口

(2) I/O 控制方式:轮询方式;中断方式;DMA 方式

(3) I/O 软件层次结构:中断处理程序;驱动程序;设备独立软件;用户层I/O 软件

(4) 输入输出应用程序接口:字符设备接口;块设备接口;网络设备接口;阻塞/非阻塞 I/O

  1. 设备独立软件

(1) 缓冲区管理;

(2) 设备分配与回收;

(3) 假脱机技术 (SPOOLing);

(4) 设备驱动程序接口

  1. 外存管理

(1) 磁盘:磁盘结构;格式化;分区;磁盘调度方法

(2) 固态硬盘:读写性能特性;磨损均衡

image-20230624183448342.png

在介绍冯·诺依曼结构计算机时, 提到输入/输出子系统(I/O子系统)是计算机的重要组成部分。无论是在应用程序员编写用户程序时,还是在最终用户基于操作系统提供的人机交互功能使用计算机时,都会涉及如何让外部设备进行I/O的问题。

输入输出组织主要用于控制外设与内存、外设与CPU之间进行数据交换,它是计算机系统中重要的软、硬件结合的子系统。通常把外部设备及其接口线路、I/O控制部件以及I/O软件统称为输入输出系统。输入输出组织要解决的问题是对各种形式的信息进行输入和输出的控制。实现输入输出功能的关键是解决以下一系列问题:

  • 如何在CPU、主存和外设之间建立一个高效的信息传输“通路”;
  • 怎样将用户的I/O请求转换成对设备的控制命令;
  • 如何对外设进行编址;
  • 怎样使CPU方便地寻找到要访问的外设;
  • I/O硬件和I/O软件如何协调完成主机和外设之间的数据传送等等。

使用高级语言编写应用程序时,通常会利用专门的I/O库函数来实现外设的I/O功能,而I/O库函数通常将具体的I/O操作功能通过相应的陷阱指令(自陷指令,有时也称为"软中断指令")以"系统调用"的方式转换为由操作系统内核来实现。也就是说,任何I/O操作过程最终都是由操作系统内核控制完成的。

本章主要介绍与I/O操作相关的软件和硬件方面的相关内容。主要内容见上述导图。

I/O子系统概述

I/O系统中各种模块之间的层次视图,本章按照该图自上而下依次介绍

1757442959016-f5bc5b9d-890e-4b40-b212-b9ef53a53e8b.png

I/O软件涉及的面很宽,往下与硬件有着密切关系,往上又与虚拟存储器系统、文件系统和用户直接交互,它们都需要I/O软件来实现I/O操作。

为使复杂的I/O软件能具有清晰的结构、良好的可移植性和易适应性,目前已普遍采用层次式结构的I/O软件。将系统中的设备管理模块分为若干个层次,每层都是利用其下层提供的服务,完成输入/输出功能中的某些子功能,并屏蔽这些功能实现的细节,向高层提供服务。整个I/O软件可以视为具有4个层次的系统结构,各层次及其功能如下:

  1. 用户层I/O软件:实现与用户交互的接口,用户可直接调用在用户层提供的、与I/O操作有关的库函数,对设备进行操作。一般而言,大部分的I/O软件都在操作系统内部,但仍有一小部分在用户层,包括与用户程序链接在一起的库函数。用户层软件必须通过一组系统调用来获取操作系统服务。
  2. 设备独立性软件:用于实现用户程序与设备驱动器的统一接口、设备命令、设备的保护及设备的分配与释放等,同时为设备管理和数据传送提供必要的存储空间。设备独立性也称设备无关性,使得应用程序独立于具体使用的物理设备。为实现设备独立性而引入了逻辑设备和物理设备这两个概念。在应用程序中,使用逻辑设备名来请求使用某类设备;而在系统实际执行时,必须将逻辑设备名映射成物理设备名使用。
使用逻辑设备名的好处
  • ①增加设备分配的灵活性;
  • ②易于实现 I/O重定向,所谓I/O重定向,是指用于I/O操作的设备可以更换(即重定向),而不必改变应用程序。为了实现设备独立性,必须再在驱动程序之上设置一层设备独立性软件。

总体而言,设备独立性软件的主要功能可分为以下两个方面

  • ①执行所有设备的公有操作,包括:对设备的分配与回收; 将逻辑设备名映射为物理设备名;对设备进行保护,禁止用户直接访问设备;缓冲管理;差错控制;提供独立于设备的大小统一的逻辑块,屏蔽设备之间信息交换单位大小和传输速率的差异。
  • ②向用户层(或文件层)提供统一接口。无论何种设备,它们向用户所提供的接口应是相同的。例如,对各种设备的读/写操作,在应用程序中都统一使用read/write命令等。

  • 设备驱动程序:与硬件直接相关,负责具体实现系统对设备发出的操作指令,驱动I/O设备工作的驱动程序。通常,每类设备配置一个设备驱动程序,它是I/O进程与设备控制器之间的通信程序,常以进程形式存在。设备驱动程序向上层用户程序提供一组标准接口,设备具体的差别被设备驱动程序所封装,用于接收上层软件发来的抽象IO要求,如read和write命令,转换为具体要求后,发送给设备控制器 ,控制I/O设备工作;它也将由设备控制器发来的信号传送给上层软件,从而为I/O内核子系统隐藏设备控制器之间的差异。

由于设备之间的差异很大,每类设备的驱动程序都不相同,故必须由设备制造厂商提供,而不是由OS设计者来设计。因此,每当在系统中增加一个新设备时,都需要安装由厂商提供的新的驱动程序。

  1. 中断处理程序:用于保存被中断进程的CPU环境,转入相应的中断处理程序进行处理,处理完毕再恢复被中断进程的现场后,返回到被中断进程。\ 中断处理层的主要任务有:进行进程上下文的切换,对处理中断信号源进行测试,读取设备状态和修改进程状态等。由于中断处理与硬件紧密相关,对用户而言,应尽量加以屏蔽,因此应放在操作系统的底层,系统的其余部分尽可能少地与之发生联系。
以用户对设备的一次命令来总结各层次的功能
  • ①当用户要读取某设备的内容时,通过操作系统提供的read命令接口,这就经过了用户层。
  • ②操作系统提供给用户使用的接口,一般是统一的通用接口,也就是几乎每个设备都可以响应的统一命令,如read命令,用户发出的read命令,首先经过设备独立层进行解析,然后交往下层。
  • ③接下来,不同类型的设备对read命令的行为会有所不同,如磁盘接收read命令后的行为与打印机接收read命令后的行为是不同的。因此,需要针对不同的设备,把read命令解析成不同的指令,这就经过了设备驱动层。
  • ④命令解析完毕后,需要中断正在运行的进程,转而执行read命令,这就需要中断处理程序
  • ⑤最后,命令真正抵达硬件设备,硬件设备的控制器按照上层传达的命令操控硬件设备,完成相应的功能。

I/O子系统工作的大致过程如下:首先,CPU在用户态执行用户进程,当CPU执行到系统调用封装函数对应的指令序列中的陷阱指令时,(每个系统调用的封装函数都会被转换为一组与具体机器架构相关的指令序列,这个指令序列中至少有一条陷阱指令,在陷阱指令之前可能还有若干条传送指令用于将I/O操作的参数送入相应的寄存器),会从用户态陷入到内核态;转到内核态执行后,CPU根据陷阱指令执行时EAX寄存器中的系统调用号,选择执行一个相应的系统调用服务例程;在系统调用服务例程的执行过程中可能需要调用具体设备的驱动程序;在设备驱动程序执行过程中启动外设工作,外设准备好后发出中断请求,CPU响应中断后,就调出中断服务程序执行,在中断服务程序中控制主机与设备进行具体的数据交换。\ 下图是Linux 系统中write操作的执行过程示意图。

FF66B13E78DB33CC01AC82ECD4942FCB.png

具体过程

如图所示,假定用户程序中有一个语句调用了库函数printf(),在printf()函数中又通过一系列的函数调用,最终转到调用write()函数。在write()函数对应的指令序列中,一定有一条用于系统调用的陷阱指令,在IA-32+Linux 系统中就是指令int $0x80或sysenter。该陷阱指令执行后,进程就从用户态陷入到内核态执行。Linux中有一个系统调用的统一入口,即系统调用处理程序system_call()。CPU 执行陷阱指令后,便转到system_call()的第一条指令执行。在system_call()中,将根据 EAX寄存器中的系统调用号跳转到当前系统调用对应的系统调用服务例程sys_write()去执行。system_call()执行结束时,从内核态返回到用户态下的陷阱指令后面一条指令继续执行。

Info

完整过程:C库函数→系统调用→系统调用中的内联汇编→执行内联汇编中的传送指令传送系统调用号与参数到寄存器中,执行trap指令陷入→trap执行完直接跳转系统调用处理程序(system_call统一接口)→根据寄存器中的系统调用号引出系统调用服务例程→系统调用程序引出设备驱动处理程序(统一接口)→设备驱动处理程序根据参数中的设备文件名找到对应设备驱动→驱动程序初始化IO接口(设置参数),选中设备后将接口的start位置1,启动设备开始传输,并且阻塞自身后调用schedual(),让出处理机

【2011-26】用户程序发出磁盘I/O请求后,系统的正确处理流程是( )。

A. 用户程序→系统调用处理程序→中断处理程序→设备驱动程序

B. 用户程序→系统调用处理程序→设备驱动程序→中断处理程序

C. 用户程序→设备驱动程序→系统调用处理程序→中断处理程序

D. 用户程序→设备驱动程序→中断处理程序→系统调用处理程序

【2012-26】用户程序发出磁盘I/O请求后,系统的正确处理流程是操作系统的I/O子系统通常由四个层次组成,每一层明确定义了与邻近层次的接口。其合理的层次组织排列顺序是( )。

A. 用户级I/O软件、设备无关软件、设备驱动程序、中断处理程序

B. 用户级I/O软件、设备无关软件、中断处理程序、设备驱动程序

C. 用户级I/O软件、设备驱动程序、设备无关软件、中断处理程序

D. 用户级I/O软件、中断处理程序、设备无关软件、设备驱动程序

【2013-25】用户程序发出磁盘 I/O 请求后,系统的处理流程是:用户程序→系统调用处理程序→设备驱动程序→中断处理程序。其中,计算数据所在磁盘的柱面号、磁头号、扇区号的程序是( )。

A. 用户程序

B. 系统调用处理程序

C. 设备驱动程序

D. 中断处理程序


用户层 I/O 软件

用户层I/O软件是整个I/O系统层次结构的最顶层,它直接面向应用程序员和最终用户。这一层的主要目标是隐藏所有底层I/O操作的复杂性,为用户提供一个简单、方便、统一的接口来执行输入输出操作 。用户可以通过调用封装在用户层的与 I/O 相关的库函数进行 I/O 操作( 这些库函数本身运行在用户态,它们本身并不直接操作硬件,而是通过调用操作系统提供的系统调用来请求内核服务,从而陷入内核态,将请求转交给下一层的“设备独立性软件”)。

上面这种是通过库函数和系统调用进行的显式 I/O 操作,这是最常见和最直接的 I/O 方式,与此同时,还有一种由虚拟内存系统自动触发的隐式 I/O 操作。例如,当一个程序试图访问一个不在物理内存的数据对应的虚拟内存地址会触发缺页异常,自动发起一次磁盘 I/O 操作;或者用户通过 mmap 系统调用将一个磁盘文件映射到自己进程的虚拟内存空间,在首次访问该地址或者修改对应地址数据都会触发磁盘 I/O。

SPOOLing 技术属于用户层 I/O 软件还是设备独立软件?

在经典操作系统教材例如汤子瀛操作系统中,SPOOLing 技术被划分为用户层 I/O 软件,而在 408 大纲中,它被划分为设备独立性软件,这该如何理解?(考试时这种有争议的问题不会出)

之所以SPOOLing 技术在很多教材被划分为用户层 I/O 软件,是因为Spooling系统的入口和部分组件确实工作在用户层:

  1. 用户接口 : 用户发起打印操作,通常是通过应用程序(如Word)的打印对话框,或者在命令行使用命令。这些应用程序和命令本身都属于用户层软件。
  2. 守护进程 : 在现代操作系统中(如Linux或Windows),Spooling系统通常由一个后台运行的守护进程或服务来管理。这个守护进程虽然执行的是系统管理任务,但它本身是一个运行在用户态的进程,而不是内核代码的一部分。它通过标准的系统调用与内核进行交互,来读写磁盘队列和访问打印机设备驱动。

而将Spooling的核心功能划分到设备独立性软件层,主要基于以下几点理由:

  1. 实现了设备共享 : 像打印机这样的设备在物理上是独占的,一次只能为一个任务服务。Spooling技术通过在磁盘上建立一个缓冲区(打印队列),将多个用户并发的打印请求有序地排队,从而将一个独占设备改造成了可共享的虚拟设备。这种设备管理和资源分配的职能,正是设备独立性软件的核心任务之一。
  2. 提供了设备无关性 : 对于上层的应用程序来说,它看到的不是一个“忙碌”或“空闲”的物理打印机,而是一个永远可用的“逻辑打印机”。应用程序只需将打印任务交给Spooling系统即可,无需关心物理打印机当前的状态。这种屏蔽底层物理设备细节、提供统一逻辑接口的做法,是“设备独立性”这个名字的完美体现。

因此,虽然用户通过用户层软件来使用Spooling服务,但Spooling服务本身的核心功能和设计思想属于设备独立性软件的范畴。

输入输出应用程序接口

1759070629311-efa9726d-54e2-4b5e-9231-bbb56902240f.png

由于不同类型的设备存在的读写方式等差异,为了应用程序访问起见,许多差异都被操作系统所隐藏,设备也被分为几种常规类型。在I/O核心子系统与高层之间的接口也被分为若干接口;

块设备接口

块设备是指数据的存取和传输是以 数据块 为单位的设备,典型的块设备是磁盘、固态硬盘、U 盘、SD 卡 、CD 等;基本特征是传输速率较高、可寻址;磁盘设备的I/O常采用DMA方式;有以下特征:

  • 可寻址/随机访问 : 这是块设备最重要的特性。你可以直接命令设备:“请读取第500号数据块”或“请向第12345号数据块写入数据”,这种能力使得文件系统可以在其上构建,实现对文件中任意位置的快速读写。 (即隐藏了磁盘的二维结构,在二维结构中,每个扇区的地址需要用磁道号和扇区号来表示,而块设备接口将磁盘的所有扇区按数据块顺序划分,这样就将二维结构变为一种线性序列)
  • 固定大小的数据单元:无论是读取还是写入,基本单位都是一个“块”。即使你只想读取1个字节,操作系统也可能会从硬件中读取整个块,然后从中提取出你需要的字节。
  • 缓冲机制 :操作系统会大量使用内存(称为Buffer Cache)来缓存块设备的数据。你请求读取的数据块如果已在缓存中,就可以直接从内存返回,极大地提高了I/O性能。同样,写入操作也可能只是先写入缓存,稍后再由操作系统统一“刷”到物理设备上。
  • 将抽象命令映射为低层操作:由于用户进程所使用的 open() 、read() / write()、 lseek() 等无法直接被设备识别并执行,块设备接口将这些命令映射为设备能识别的具体操作。

字符设备接口(字符流接口)

字符设备是指数据的存取和传输是以字符为单位 的设备,如键盘、打印机、鼠标等。传输速率较低、不可寻址,并且在输入/输出时通常采用中断驱动方式。具体来说有以下特征:

  • 流式/顺序访问 (不可寻址) : 数据就像水流一样,你只能从当前位置顺序地读取或写入,不能跳跃。它没有“块”的概念,也没有地址。由于字符设备不可寻址,只能采取顺序存取方式,通常为字符设备建立一个字符缓冲区,用户程序通过get()操作从缓冲区获取字符,通过put()操作将字符输出到缓冲区。
  • 大多数字符设备(如打印机、串口等)属于独占设备,为此接口中还需要提供打开和关闭操作来获取和释放访问权限,以实现互斥共享。
  • 控制命令丰富: 字符设备通常支持一个特殊的ioctl()系统调用,用于进行设备特定的设置,如设置串口的波特率等。

网络设备接口

网络设备接口是一套专门用于和其他计算机进行数据交换的接口。它不直接与读写相关,而是围绕着数据包的收发和连接的管理来设计的,典型设备有以太网卡,它有以下关键特征:

  • 不使用常规文件API: 应用程序通常不会通过open然后read/write的方式来操作网卡。它使用一套完全独立的、称为套接字(Socket)的API;
  • 数据包导向:数据以网络数据包的形式进行封装和传输。每个数据包都包含了目标地址、源地址等信息。
  • 连接管理:接口需要处理复杂的网络概念,如建立连接(TCP)、无连接通信(UDP)、监听端口、处理超时等。
  • 异步通信:网络是不可靠且有延迟的,因此网络接口本质上是异步的。你发送一个数据包,但不知道它何时到达,也不知道对方何时会回复。
  • 主要API/系统调用 (Socket API): socket()(创建一个通信端点)、bind(): 将一个地址(IP地址+端口号)绑定到套接字上、send() / recv(): 发送和接收数据包、close(): 关闭连接和套接字。

1759070629470-33f9538b-3f62-4a80-a859-f4d594fa1983.png

I/O 模型:阻塞 I/O 与非阻塞 I/O

以一次典型的I/O操作read为例,包含两个独立的阶段:

  1. 等待数据准备: 系统内核等待硬件上的数据到达。例如,等待键盘输入、等待磁盘寻道并读取数据、等待网络数据包到达。
  2. 数据从内核复制到用户空间: 数据准备好后,需要将其从内核的缓冲区复制到应用程序指定的内存地址。

阻塞与非阻塞的核心区别,就在于它们如何处理第一个阶段——“等待数据准备”。

阻塞I/O

这是最常见、最简单的I/O模型。当应用程序发起一个I/O系统调用(如read)时,如果内核发现数据还没有准备好,它不会立即返回。相反,操作系统会将这个应用程序的线程/进程从“运行”状态切换到“等待(阻塞)”状态。此时,CPU可以去执行其他线程/进程。直到数据完全准备好,内核才会唤醒该线程,继续执行系统调用服务例程将数据从内核空间复制到用户空间后返回用户态,程序继续执行。

可以类比于你去食堂打饭,但菜还没做好。于是你只能站在打菜窗口前死等,什么也干不了。直到厨师把菜做好(数据准备),并且食堂阿姨把菜打到你的餐盘里(数据复制)之后,你才能端着饭离开。

优点:代码逻辑是线性的、顺序的,非常直观易懂。数据 = read(),下一行代码执行时,数据一定是有效的。

缺点:并发能力差,一个线程在任何时刻只能处理一个I/O请求。在等待I/O时,整个线程被完全挂起,造成了计算资源的浪费。如果大量线程都因I/O而阻塞,系统的吞吐量会急剧下降。

非阻塞I/O

当应用程序发起一个I/O系统调用时,如果内核发现数据还没有准备好,它会立即返回一个错误码。它不会让线程进入等待状态。应用程序收到这个错误码后,就知道数据还没准备好。

线程可以先去处理其他任务,然后反复地、主动地去调用这个I/O系统调用,检查数据是否准备好了。这个反复查询的过程被称为“轮询”。一旦轮询发现数据已准备好,此时再进行I/O调用把内核缓冲区的数据复制到用户空间。

可以类比于你到食堂问阿姨菜做好了没,阿姨立刻告诉你:“没呢!” 你听完马上就离开,可以去玩会儿手机或看会儿书。但你需要每隔几分钟就跑回去问一次:“阿姨,现在好了吗?” 直到有一次阿姨说:“好了!” 然后你站在窗口前,等待阿姨把菜打到你餐盘里,然后离开。

优点:具有高并发潜力,单个线程可以在等待一个I/O操作的同时,去处理其他计算任务,或者去轮询其他的I/O通道。线程的利用率大大提高,使得一个线程管理多个连接成为可能。

缺点:编程模型复杂,应用程序需要编写一个循环来不断轮询,这会使代码逻辑变得复杂;CPU资源消耗,在轮询的循环中,即使大部分时间I/O都没有就绪,这个循环本身也在消耗CPU时间(“忙等待”)。

为什么非阻塞I/O的并发度更高?

核心在于线程资源的释放。 在阻塞模型下,一个线程与一个I/O通道“绑定等死”,线程的生命周期被漫长的I/O等待所占据。而在非阻塞模型下,线程在发起I/O调用后立即被“释放”,它可以转而去为其他成千上万个I/O通道服务(去轮询它们的状态),或者执行其他计算任务。这就好比一个服务员(线程)可以同时照看很多张桌子(I/O通道),而不是站在一张桌子旁死等客入吃完饭。

设备独立性软件(与设备无关的I/O软件)

为什么需要设备独立性软件?

如果没有这一层软件,会发生什么?

  • 对于应用程序开发者: 如果您想编写一个“保存文件”的功能,您需要为三星的硬盘写一套代码,为西部数据的硬盘写另一套,为金士顿的U盘再写一套……因为它们的硬件指令、内部块大小等细节都可能不同。应用程序将变得极其复杂且毫无可移植性。
  • 对于操作系统开发者: 每当市场上出现一款新硬件,整个操作系统的上层代码(如文件系统)可能都需要修改以适配它。这会让操作系统变得难以维护和扩展。

核心矛盾: 硬件世界是多样、具体、复杂的,而软件世界追求的是统一、抽象、简单。设备独立性软件就是为了解决这个矛盾而生的“翻译官”和“协调员”。

设备独立性软件是位于用户层I/O软件和设备驱动程序之间的一个核心软件层。它的主要目标是屏蔽所有设备的物理细节,执行所有I/O设备的公共操作,并向上层提供一个统一、简洁、标准的接口(也就是所谓的输入输出应用程序接口)。

可以把整个I/O系统想象成一辆汽车:

  • 应用程序 (司机): 想要达到“把数据显示在屏幕上”或“把文件存入硬盘”的目的。
  • 设备独立性软件 (方向盘、油门、刹车踏板、档位杆): 这是司机与汽车交互的标准接口。无论这辆车是V8引擎、涡轮增压引擎还是电动机,这套驾驶接口都是统一的。司机只需要学会这套标准操作即可。
  • 设备驱动程序 (引擎控制单元、变速箱逻辑): 这部分与具体硬件紧密相关。它负责将“踩下油门踏板30%”这个标准指令,翻译成“向V8引擎喷射X量的燃油”或者“向电动机输送Y安培的电流”这种具体指令。
  • 硬件设备 (引擎、车轮): 实际执行工作的物理部件。

应用程序(司机)只与标准接口(方向盘、踏板)打交道,而无需关心底层硬件(引擎)的具体实现。

设备无关性优点

  • 简化应用程序开发:程序员无需为每一种可能遇到的硬件设备编写不同的代码。他们只需要面向操作系统提供的标准I/O接口编程即可。
  • 提高程序可移植性:一个使用了标准I/O接口的程序,可以不加修改地在任何支持这些接口的操作系统和硬件平台上运行。
  • 便于添加新设备:当一个新的硬件设备被发明出来时,硬件厂商只需要为其编写一个符合操作系统规范的设备驱动程序即可。操作系统的核心部分(设备无关性软件)和所有现存的应用程序都无需任何改动,就能使用这个新设备。这极大地增强了操作系统的可扩展性。
  • 系统维护性:将I/O系统分层,使得各层功能清晰,降低了系统的复杂性,易于维护和升级。

Info

设备独立性软件向上层的应用程序提供IO应用程序接口(如块设备接口、字符设备接口等),同时向下层定义了一套设备驱动程序接口,并调用(或消费)由具体设备驱动程序所实现的这些接口。

设备无关性软件通过执行以下关键任务来实现其目标:

  1. 设备命名 :将设备从物理名称(如复杂的主板总线地址)映射到逻辑名称或符号名称(如 /dev/sda1 代表第一个硬盘的第一个分区),这种命名方式方便用户和程序记忆与使用。
  2. 设备保护:检查用户进程是否有权限访问某个设备。例如,一个普通用户进程可能被禁止直接对硬盘的原始扇区进行写操作,以防破坏文件系统。
  3. 设备的分配与回收:管理对设备的访问。对于某些设备(如打印机),在同一时间只允许一个进程使用(独占设备)。这一层负责处理设备的分配和回收。
  4. 提供与设备无关的块大小:不同的物理设备(如硬盘、SSD、U盘)可能有不同的物理扇区大小(512字节, 4KB等)。设备无关性软件可以向上层提供一个统一的、逻辑的块大小(例如,统一为4KB),屏蔽掉底层的物理差异,简化文件系统的设计。
  5. 缓冲 和 缓存
  6. 缓冲: 为了匹配CPU/内存与I/O设备之间巨大的速度差异,它提供了缓冲区。例如,当程序写入数据时,可以快速写入内存中的缓冲区然后立即返回,由操作系统稍后慢慢地将缓冲区数据写入慢速的硬盘。
  7. 缓存: 将频繁访问的磁盘数据块保留在内存中,当程序再次请求时,直接从高速内存返回,避免了对慢速磁盘的重复访问。
  8. 提供设备驱动程序接口:设备无关性软件规定了一套标准的接口,用于接入不同设备的驱动程序。

磁盘高速缓存

目的:为了充分利用数据访问的局部性特点,操作系统通常在内存中的内核空间开辟高速缓存,将大多数最近从块设备(如磁盘)读出或写入的数据保存在作为高速缓存的RAM区中。磁盘高速缓存逻辑上属于磁盘,物理上则是驻留在内存中的盘块;

特点:磁盘高速缓存技术不同于通常意义下的介于CPU和内存之间的小容量高速存储器(Cache),而是指利用内存中的存储空间来暂存从磁盘中读出的一系列盘块中的信息。


读取操作:当一个应用程序请求读取磁盘上的数据时:

  1. 检查缓存: 操作系统首先检查请求的数据块是否已经在磁盘缓存中。
  2. 缓存命中 : 如果在,操作系统直接从高速的内存(缓存)中复制数据给应用程序。这次I/O请求没有发生任何实际的磁盘操作,速度极快。
  3. 缓存未命中 : 如果不在,操作系统会发起一次真正的磁盘I/O。数据从磁盘被读取到磁盘缓存中,然后再从缓存复制给应用程序。虽然这次操作较慢,但它为下一次可能的访问做好了准备(利用了时间局部性)。

写入操作比读取更复杂,因为它涉及数据一致性和安全性的权衡。主要有两种策略:

  • 写通 (直写):数据同时写入缓存和磁盘。只有当数据被写入物理磁盘后,系统调用才会返回,应用程序才能继续。
  • 优点: 非常安全。即使系统立即断电,数据也不会丢失。
  • 缺点: 性能提升有限,因为应用程序仍然需要等待慢速的磁盘写入完成。
  • 回写:这是现代操作系统普遍采用的策略,当程序写入数据时,数据只被写入缓存,同时该缓存块被标记为“脏 (dirty)”。然后系统调用立即返回,应用程序可以继续执行,感觉写入操作瞬间完成。操作系统会在之后的某个“方便”的时刻(如系统空闲时、缓存需要空间时、或定时任务),才将所有“脏”的缓存块一次性地“刷”回磁盘。
  • 优点: 写入性能极高,大大提升了系统响应速度。还能合并多次对同一块的写入,减少磁盘I/O次数。
  • 缺点: 有数据丢失的风险。如果在“脏”数据被刷回磁盘前系统崩溃或断电,这部分在缓存中的修改将会永久丢失。这也是为什么有时强制关机会导致文件损坏的原因。

在内存中的两种形式:

  • 开辟一块单独固定的内存空间;
  • 把未利用的内存空间作为一个缓冲池,供请求分页系统和磁盘I/O分时共享;

磁盘高速缓存在现代 OS 中的应用

  1. 页缓存 (Page Cache):文件数据的核心缓存(文件内容在内存中的“副本”)

  2. 缓存对象: 文件的数据内容本身,以及通过mmap映射的内存区域。

  3. 工作单位:内存页 (Page),这使得它能与系统的虚拟内存管理无缝集成,效率极高。
  4. 核心职责: 当您读取文件时,内核会先在页缓存中查找。写入文件时,通常也是先写入页缓存(回写模式),然后由内核在后续某个时刻同步到磁盘。几乎所有的文件I/O都会经过它。

  5. 目录项缓存 (Dentry Cache):为了解决“查找文件”这一高频操作而设计的缓存。

  6. 缓存对象: 目录项 (Directory Entry),也就是文件名和其对应的索引节点 (inode) 编号之间的映射关系。

  7. 核心职责: 当您要打开一个路径,比如 /home/user/file.txt,内核需要逐级解析这个路径:
  8. 在根目录 / 中找到 home 目录的inode编号。
  9. 在 home 目录中找到 user 目录的inode编号。
  10. 在 user 目录中找到 file.txt 文件的inode编号。 每一步都可能需要读取磁盘上的目录文件。Dentry缓存将这些“文件名 -> inode编号”的查找结果保存在内存中。如果一个路径的所有组成部分都在Dentry缓存中,那么整个路径解析过程就可以完全在内存中完成,无需任何磁盘I/O。

  11. 索引节点缓存 (inode Cache):当Dentry缓存帮我们找到了文件的inode编号后,inode缓存就登场了。

  12. 缓存对象:索引节点 (inode) 本身,这个结构体包含了文件的所有元数据 (Metadata):权限、所有者、大小、创建/修改时间,以及指向文件数据块的指针等。

  13. 核心职责: 将磁盘上存储的inode结构体缓存在内存中。当内核通过Dentry缓存拿到inode编号后,它会紧接着查询inode缓存,以获取该文件的所有属性信息。如果没有这个缓存,每次获取文件属性(例如 ls -l 命令)都需要一次磁盘读取,系统会变得极慢。

  14. 缓冲区缓存 (Buffer Cache):块设备的“对接层”

  15. 缓存对象:磁盘块的元信息,以及与Page Cache关联的缓冲区头

  16. 核心职责: 在现代内核中,它不再是文件数据缓存的主力(这个工作已交给Page Cache)。它的主要职责变成了:缓存文件系统的元数据块: 如超级块 (Superblock)、块分配位图、inode 所在磁盘块等,这些数据不属于任何一个文件,但对文件系统至关重要。

【2015-28】在系统内存中设置磁盘缓冲区的主要目的是( )。

A. 减少磁盘I/O次数

B. 减少平均寻道时间

C. 提高磁盘数据可靠性

D. 实现设备无关性

解析

在系统中设置磁盘缓冲区(通常称为Disk Cache)的最主要、最根本的目的是缓和CPU/内存与磁盘之间巨大的速度差异。磁盘(尤其是机械硬盘)是一种速度极慢的设备,其访问速度与内存相差数个数量级。磁盘缓冲区作为位于高速内存中的一块区域,通过减少对慢速磁盘的直接访问次数,从而极大地提升系统整体的I/O性能。

正确选项A :磁盘缓冲区通过以下两种主要机制来减少物理磁盘的I/O次数:

  1. 缓存读取 (Caching for Reads):
  • 当应用程序需要读取数据时,操作系统会首先检查请求的数据是否已经存在于磁盘缓冲区中。
  • 缓存命中 (Cache Hit): 如果数据已在缓冲区中,操作系统会直接从高速的内存中将数据返回给应用程序,完全避免了一次物理磁盘I/O操作。
  • 缓存未命中 (Cache Miss): 如果数据不在缓冲区中,操作系统才会启动物理磁盘I/O,将数据从磁盘读入缓冲区,然后再提供给应用程序。
  • 根据程序的局部性原理(一个数据被访问后,它和它附近的数据很可能在短期内被再次访问),缓存的命中率通常很高,从而显著减少了读操作的I/O总数。
  1. 缓冲写入 (Buffering for Writes):
  • 当应用程序需要写入数据时,操作系统可以将数据先写入缓冲区,并立即通知应用程序“写入完成”,让程序继续执行,而无需等待慢速的磁盘。
  • 这种技术被称为“延迟写入”或“写回缓存”(Write-back Caching)。
  • 它不仅提升了程序的响应速度,更重要的是,它可以通过合并与排序来减少I/O次数。例如:
    • 合并写入: 如果一个程序在短时间内多次修改同一磁盘块,缓冲区中只会保留最终的版本,最后只需要进行一次物理写入操作。
    • 批量写入: 多个对不同位置的小数据写入请求可以被收集在缓冲区中,然后合并成一次较大规模的物理写入,提高了磁盘的写入效率。

B. 减少平均寻道时间: 这是一个次要的、衍生的好处,而非主要目的。当缓冲区中积累了多个I/O请求后,操作系统中的磁盘调度算法(如电梯算法)可以对这些请求进行排序,使得磁头的移动路径最短,从而减少了平均寻道时间。但是,这种优化是建立在“必须进行I/O”的前提下的。缓冲区的首要目标是通过缓存命中来完全避免I/O,这比优化一次I/O内部的时间(如寻道时间)更为根本和有效。

C. 提高磁盘数据可靠性: 这个说法是错误的。恰恰相反,延迟写入(Write-back)的缓冲策略在提升性能的同时,降低了数据的即时可靠性。如果在数据写入缓冲区但尚未同步到物理磁盘时系统突然断电,那么这部分数据将会永久丢失。为了解决这个问题,现代文件系统引入了日志(Journaling)等更复杂的技术来保证数据一致性,但这恰恰说明了缓冲区本身是为了性能而非可靠性。

D. 实现设备无关性: 这是由操作系统中的设备驱动程序和文件系统这两个层次来实现的,与缓冲区无关。设备无关性指的是应用程序使用统一的接口(如read, write)来访问设备,而无需关心底层是HDD、SSD还是U盘。缓冲区是I/O子系统中的一个性能优化部件,而不是实现设备抽象的关键层次。

以 打开并读取文件 /home/user/file.txt为例穿越讨论过的所有缓存层

第一步: open("/home/user/file.txt", O_RDONLY) 系统调用

场景一:理想情况(所有缓存全部命中)
  1. 发起调用: 应用程序调用 open(),程序从用户态陷入内核态。
  2. 路径解析开始 (VFS层):
    • 查询Dentry缓存: 内核需要将路径 /home/user/file.txt 拆分并逐级查找。
      • 它首先在Dentry缓存中查找 home (相对于根目录 /)。命中! 立刻获得home目录的inode编号。
      • 接着查找 user (相对于home)。命中! 获得user目录的inode编号。
      • 最后查找 file.txt (相对于user)。命中! 获得file.txt的inode编号。
  1. 获取文件属性:
    • 查询inode缓存: 内核使用上一步获得的file.txt的inode编号,在inode缓存中查找对应的inode对象。命中! 内核立刻获得了文件的所有元数据(权限、所有者、大小等)而无需访问磁盘。
  1. 权限检查: 内核根据内存中的inode信息,检查当前进程是否有权限以只读方式打开该文件。检查通过。
  2. 返回结果: 内核在进程的文件描述符表中创建一个新条目,指向一个代表这个已打开文件的内核对象,并最终将这个条目的索引作为文件描述符返回给应用程序。

结论: 在全部缓存命中的情况下,open 操作完全在内存中完成,没有任何磁盘I/O。

场景二:复杂情况(相关缓存均未命中)
  1. 发起调用: 同上。
  2. 路径解析 (Dentry缓存未命中):
    • 内核开始解析路径,但在查找 file.txt (在user目录下) 时,Dentry缓存未命中。
    • 内核此时必须亲自读取 user 目录文件的内容,来查找 file.txt 的条目。
    • 内核向页缓存(Page Cache)请求user目录文件的数据块。页缓存也未命中。
    • 内核被迫发起磁盘I/O,从磁盘读取user目录文件的数据块,并将其加载到页缓存中。
    • 现在,内核可以从内存(页缓存)中解析user目录的内容,找到了file.txt对应的inode编号。同时,它将这个“file.txt -> inode编号”的映射关系存入Dentry缓存。
  1. 获取文件属性 (inode缓存未命中):
    • 内核拿着新找到的inode编号,去inode缓存中查找。再次未命中。
    • 内核根据文件系统的元数据计算出该inode在磁盘上的物理位置(在哪个块,偏移多少)。
    • 内核向块设备层请求读取这个inode所在的磁盘块。这个请求会先经过缓冲区缓存,发现也没有。
    • 内核发起第二次磁盘I/O,读取inode所在的块,并将其加载到缓冲区缓存。
    • 内核从缓冲区缓存的原始数据中,解析出file.txt的inode结构,并将其存入inode缓存。
  1. 权限检查与返回: 同理想情况,但此时使用的是刚刚从磁盘加载并缓存起来的inode。

结论: 在缓存未命中的情况下,open 操作可能触发多次磁盘I/O(用于读取目录内容和文件的inode),并将结果填充到各级缓存中,为下一次访问铺平道路。

第二步: read(fd, buffer, N_bytes) 系统调用

read 操作的核心目的是将文件的数据内容,从内核空间复制到用户空间的buffer中。

场景一:理想情况(页缓存命中)
  1. 发起调用: 应用程序调用read()。此时内核已经通过fd拥有了文件的所有上下文信息(包括已缓存的inode)。
  2. 定位数据: 内核根据文件当前的读写偏移量,计算出需要读取的数据对应在文件的哪些页(Page)上。
  3. 查询页缓存: 内核到页缓存(Page Cache)中查找这些页。命中! 文件的数据已经在内存里了。
  4. 数据复制: 内核将数据从页缓存直接复制到应用程序提供的用户空间buffer中。
  5. 返回结果: 更新文件读写偏移量,并返回成功读取的字节数。

结论: 在页缓存命中的情况下,read 操作也完全在内存中完成,没有任何磁盘I/O,本质上是一次内存到内存的拷贝。

场景二:复杂情况(页缓存未命中)
  1. 发起调用: 同上。
  2. 定位与查询 (页缓存未命中): 内核在页缓存中查找所需的数据页,但未命中。
  3. 查找数据位置: 内核查看已在inode缓存中的文件inode,计算出所需数据在物理磁盘上的确切块地址。
  4. 发起磁盘I/O: 内核向块设备层发出请求,读取这些数据块。这些请求会先经过缓冲区缓存,如果之前没有其他程序恰好读过这些裸块,那么也会未命中。
  5. 物理读取与填充: 内核发起真正的磁盘I/O,从磁盘读取数据。
    • 读取到的数据块被用来填充到页缓存中(通过缓冲区缓存作为媒介)。
    • 操作系统通常会进行预读入,即除了读取当前请求的块,还会一并读取后续的几个块,并也放入页缓存,因为它猜测你马上就会需要它们(空间局部性原理)。
  1. 数据复制与返回: 一旦数据被加载到页缓存,流程就回到了理想情况的第4步。内核将数据从刚刚填充好的页缓存复制到用户buffer,然后返回。

结论: 在页缓存未命中的情况下,read 操作会触发一次(或多次,取决于读取大小和预读策略)磁盘I/O,其主要目的是将数据从磁盘搬运到页缓存中。这次读取会比较慢,但它会使后续对相同或相邻数据的读取变得飞快。

缓冲区管理

在现代操作系统中,几乎所有的I/O设备在于处理机交换数据时都用了缓冲区。缓冲区是一个存储区域,它可以由专门的硬件寄存器组成,但由于硬件的成本较高,容量也较小,一般仅用在对速度要求非常高的场合,如存储器管理中所用的联想存储器TLB(由于对页表的访问频率极高,因此使用速度很快的TLB来存放页表项的副本)、设备控制器中用的数据缓冲寄存器等。在一般情况下,更多的是利用内存作为缓冲区。本节所要介绍的也正是由内存组成的缓冲区。缓冲区管理的主要功能是组织好这些缓冲区,并提供获得和释放缓冲区的手段。

每个设备的I/O都需要使用缓冲区,因而缓冲区的申请和管理等处理是所有设备公共的,包含在与设备无关的I/O软件部分;

  1. 引入缓冲区的目的(原因)
缓和CPU和I/O设备间速度不匹配的矛盾;

事实上,凡在数据到达速率与其离去速率不同的地方,都可设置缓冲区,以缓和它们之间速率不匹配的矛盾。众所周知,CPU的运算速率远远高于I/O设备的速率,如果没有缓冲区,在输出数据时,必然会由于打印机的速度跟不上,而使CPU停下来等待;然而在计算阶段,打印机又空闲无事。如果在打印机或控制器中设置一缓冲区,用于快速暂存程序的输出数据,以后由打印机“慢慢地”从中取出数据打印,这样,就可提高CPU的工作效率。类似地,在输入设备与CPU之间设置缓冲区,也可使CPU的工作效率得以提高。

减少对CPU的中断频率,放宽对CPU中断响应时间的限制;

在远程通信系统中,如果从远地终端发来的数据仅用一位缓冲来接收,如图所示,则必须在每收到一位数据时便中断一次CPU,这样,对于速率为9.6kb/s的数据通信来说,就意味着其中断CPU的频率也为9.6kb/s,即每100μs就要中断CPU一次,而且CPU必须在100μs内予以响应,否则缓冲区内的数据将被冲掉。倘若设置一个具有8位的缓冲(移位)寄存器,如图所示,则可使CPU 被中断的频率降低为原来的1/8:若再设置一个8位寄存器,如图所示,则又可把CPU对中断的响应时间从100μs放宽到800μs。类似地,在磁盘控制器和磁带控制器中,都需要配置缓冲寄存器,以减少对CPU的中断频率,放宽对CPU中断响应时间的限制。随着传输速率的提高,需要配置位数更多的寄存器进行缓冲。

 题图

解决数据粒度不匹配的问题

缓冲区可用于解决在生产者和消费者之间交换的数据粒度(数据单元大小)不匹配的问题。例如,生产者所生产的数据粒度比消费者消费的数据粒度小时,生产者进程可以一连生产好几个数据单元的数据,当其总和已达到消费者进程所要求的数据单元大小时,消费者便可从缓冲区中取出消费。反之,如果生产者所生产的数据粒度比消费者消费的数据粒度大时,生产者每次生产的数据消费者可以分几次从缓冲区中取出消费。

提高CPU和I/O设备之间的并行性

缓冲区的引入可显著地提高CPU和I/O设备间的并行操作程度,提高系统的吞吐量和设备的利用率。例如,在CPU(生产者)和打印机(消费者)之间设置了缓冲区后,生产者在生产了一批数据并将它放入缓冲区后,便可立即去进行下一次的生产。与此同时,消费者可以从缓冲区中取出数据消费,这样便可使CPU与打印机处于并行工作状态。


  1. 缓冲区的基本思想: 当进程与设备执行数据交换时,先向系统申请一个缓冲区,然后由进程或设备将数据送至缓冲区,待缓冲区填满或数据输入完成后时,将缓冲区中的数据送给设备或进程。缓冲区为空时,才能向缓冲区输入数据;缓冲区的数据填满时,才能从缓冲区输出数据。

缓冲 (buffer) 和缓存 (cache) 是两个相似而又有区别的概念。 二者都是一段临时存储区,都能用来协调高速设备(比如处理器)与低速设备(比如硬盘、内存或者输入设备)之间的速度差异,都能提高计算机系统的效率。二者区别在于工作原理不同:缓冲是一个“中转站”,而缓存是数据源的副本。 缓冲区中的数据可以是唯一的;数据源将数据发往缓冲区后就可以不再保留;但缓存保存的数据一定是数据源中数据的子集。

特性 缓冲 (Buffer) 缓存 (Cache)
核心目的 缓和速度/粒度不匹配 加速对数据的重复访问
工作模式 数据的“中转站” 数据源的“高速副本”、“快捷方式”
数据性质 中转数据,可能是唯一的存在 源数据的副本
数据流向 通常是单向的,被消费后即失效 可以被反复读取
性能指标 关注吞吐量 关注命中率
  1. 关于缓冲区和用户进程的工作区的详细解释:我们所说的缓冲区是在内核空间里的系统缓冲区,而工作区则是在用户进程空间里的缓冲区;当然二者都是在内存中。

Info

用户进程在提出I/O请求时,指定的用来存放I/O数据的缓冲区在用户空间中。例如,文件读函数fread(buf,size,num,fp)中的缓冲区buf在用户空间中。通过陷阱指令陷入到内核态后,内核通常会在内核空间中再开辟一个或两个缓冲区,这样,在底层I/O软件控制设备进行I/O操作时,就直接使用内核空间中的缓冲区来存放I/O数据。为何不直接使用用户空间缓冲区呢?因为,如果直接使用用户空间缓冲区(即工作区),那么,在外设进行I/O期间,由于用户进程被挂起而使用户空间的缓冲区所在页面可能被替换出去,这样就无法获得缓冲区中的I/O数据。其他原因包括:可解决不同块设备读写单位的不一致、便于共享等。

另外由于缓冲区是共享资源,生产者与消费者在使用缓冲区时必须互斥,因此:

  • 当缓冲区数据非空时,不能往缓冲区冲入数据,只能从缓冲区把数据传出;
  • 当缓冲区为空时,可以往缓冲区冲入数据,但必须把缓冲区充满以后,才能从缓冲区把数据传出。

  1. 根据系统设置缓冲器的个数,缓冲技术可以分为以下几种:

Tip

在研究每块数据的处理时间时,有一个技巧:假设一种初始状态,然后计算下一次到达相同状态时所需要的时间,就是处理一块数据所需要的时间。

(1)单缓冲(sinble buffder)重点

假设某用户进程请求某种块设备读入若干块的数据。若采用单缓冲的策略,操作系统会在主存(内核空间)中为其分配一个缓冲区(若题目中没有特别说明,一个缓冲区的大小就是一个块)。

在块设备输入时,假定从磁盘把一块数据输入到缓冲区的时间为\(T\),操作系统将该缓冲区中的数据传送到用户进程工作区的时间为\(M\),而CPU对这一块数据处理的时间为\(C\)。

在单缓冲中, 假设初始状态为:工作区是满的,缓冲区是空的。(如题目无明确说明,通常认为缓冲区的大小和工作区的大小相等).

  • 假设\(T>C\),从初始状态开始,当工作区数据处理完后,时间为\(C\),缓冲区还没充满,当缓冲区充满时,经历了\(T\)时间,停止再冲入数据,然后缓冲区向工作区传送数据,当工作区满了后,缓冲区的数据同时也为空,用时为M,到达下一个开始状态,整个过程用时\(M+T\);
  • 若\(T\<C\),同理,整个过程用时 \(M+C\)。

故单缓冲区处理每块数据的用时为\(Max(C,T)+M\)。

1760024438785-566911fa-6448-4331-9e82-3c907747f2dc.png

Danger

【注】:由上图可知:n次传输耗时为\((n-1)\*[Max(C,T)+M]+(C+T+M)\),即前\(n-1\)次为并行,最后一次为串行收尾;( 前n-1个数据块的处理时间可以看作是并行的准备阶段和串行的传送阶段,而最后一个数据块需要经历完整的串行收尾(输入、传送、处理) )


(2) 双缓冲(Double Buffer)重点

由于缓冲区是共享资源,生产者与消费者在使用缓冲区时必须互斥。如果消费者尚未取走缓冲区中的数据,即使生产者又生产出新的数据,也无法将它送入缓冲区,生产者等待。如果为生产者与消费者设置了两个缓冲区,便能解决这一问题。因此为了提高设备利用率,入们引入了双缓冲区机制,在设备输入时,先将数据送入第一缓冲区,装满后便转向第二缓冲区;

双缓冲题目中,假设初始状态为:工作区空,其中一个缓冲区满,另一个缓冲区空

1760259351384-d40ef57b-8556-46c1-95ab-c20e2022b72e.png

汤书中的双缓冲区工作示意图

Warning

结论: 采用双缓冲策略,处理与传送串行,传送与输入并行,综上处理一个数据块的平均耗时为\(Max (T, C+M)\);

【注】:因此\(n\)次传输耗时为\((n-1)\*[Max(T,C+M)]+(C+T+M)\),即前\(n-1\)次为并发,最后一次为串行收尾;


使用单/双缓冲在通信时的区别

两台机器之间通信时,可以配置缓冲区用于数据的发送和接收。

1760260484095-beba9678-de8d-40c7-9848-202518a40c6a.png


(3) 循环缓冲区(环形缓冲区)

如果进程需要执行大量的I/O操作,那么仅有双缓冲区并不够,此时通常需要使用多于两个的缓冲区方案来弥补需求的不足;所谓循环缓冲区,包含很多大小相同的缓冲区,每个缓冲区中有一个链接指针指向下一个缓冲区,最后一个缓冲区指针指向第一个缓冲区,多个缓冲区构成一个环形(循环队列);如图,in 指向输入位置,out 指向输出位置。

1760262868834-95fcb300-71ec-494b-a83a-3c2e37ad71f7.png


(4) 缓冲池

上述的缓冲区是专门为特定的生产者和消费者进程设置的,它们属于专用缓冲。当系统较大时,应该有许多这样的循环缓冲,这不仅要消耗大量的内存空间,而且其利用率不高。为了提高缓冲区的利用率,目前广泛流行既可用于输入又可用于输出的公用缓冲池,在池中设置了多个可供若干个进程共享的缓冲区。

缓冲池与缓冲区的区别在于:缓冲区仅仅是一组内存块的链表,而缓冲池则是包含了一个管理的数据结构及一组操作函数的管理机制,用于管理多个缓冲区。

缓冲池由系统中共用的缓冲区组成,通常将缓冲池中具有相同类型的缓冲区链接成一个队列,按使用状况可形成以下三个队列:

  1. 空白缓冲队列:由空缓冲区链成的队列,用于取出空缓冲区来进行写入操作。
  2. 输入队列:装满输入数据的缓冲区链成的队列,用于保存输入设备输入的数据,供用户程序读取。
  3. 输出队列:装满输出数据的缓冲区链成的队列,用于保存用户程序输出到设备的数据, 等待被输出设备读取 。

另外,根据一个缓冲区在实际运算中扮演的功能不同,又设置了四种工作缓冲区:

  • 针对缓冲池与I/O设备的:用于收容输入数据的工作缓冲区(hin)、用于提取输出数据的工作缓冲区(sout)
  • 针对缓冲池与用户进程空间的:用于提取输入数据的工作缓冲区(sin)、用于收容输出数据的工作缓冲区(hout)

1760263685570-fec6bfa6-bad7-4704-a500-0f0a47f3c186.png

h代表host/用户进程,s代表system/设备,in/out代表方向

1760271291673-12fbf542-ebbd-4cbc-acae-6e248198fd44.png

Info

看着复杂,其实原理很简单,不管是哪个队列,只要是取出操作,都是从队头取;只要是挂入队列,都是挂到队尾;以输入为例,先从空缓冲队列头部取一个缓冲区接收输入,然后给它挂到输入队列尾部;提取输入时再从输入队列头部取出一个缓冲区把里面的数据取出,再把空的缓冲区挂到空缓冲队列的尾部即可。

具体工作方式如图所示

  1. 收容输入:输入进程从空缓冲队列的队首摘下一空缓冲区,作为收容输入工作缓冲区,然后把数据输入其中,装满后再将它挂在输入队列队尾。
  2. 提取输入:计算进程从输入队列的队首取得一个缓冲区,作为提取输入工作缓冲区,从中提取数据,用完数据后将它挂在空缓冲队列队尾。
  3. 收容输出:计算进程从空缓冲队列的队首取得一空缓冲区,作为收容输出工作缓冲区,当其中装满数据后,将其挂在输出队列末尾。
  4. 提取输出:输出进程从输出队列的队首取得一装满输出数据的缓冲区,作为提取输出工作缓冲区,在数据提取完后,再将它挂在空缓冲队列末尾。

Danger

[注]:单缓冲、双缓冲、循环缓冲为生产者消费者进程专用缓冲,而缓冲池为进程共享缓冲(请求分页中可变分配局部置换、可变分配全局置换中予以分配的系统空页队列)

【2011-31】某文件占10个磁盘块,现要把该文件磁盘块逐个读入主存缓冲区,并送用户区进行分析,假设一个缓冲区与一个磁盘块大小相同,把一个磁盘块读入缓冲区的时间为100μs,将缓冲区的数据传送到用户区的时间是50μs,CPU对一块数据进行分析的时间为50μs。在单缓冲区和双缓冲区结构下,读入并分析完该文件的时间分别是( )。

A. 1500μs、1000μs

B. 1550μs、1100μs

C. 1550μs、1550μs

D. 2000μs、2000μs

解析

本题选 B。

直接代入上面推导得到的公式,本题中,公式

在单缓冲区读入并分析完该文件的时间是公式。

在双缓冲区读入并分析完该文件的时间是公式

【2013-27】设系统缓冲区和用户工作区均采用单缓冲,从外设读入 1 个数据块到系统缓冲区的时间为 100,从系统缓冲区读入 1 个数据块到用户工作区的时间为 5,对用户工作区中的 1 个数据块进行分析的时间为 90(如下图所示)。

1757352062998-1f100f76-574e-40eb-8271-626c8dcb1dd2.jpeg

进程从外设读入并分析 2 个数据块的最短时间是( )。

A. 200

B. 295

C. 300

D. 390

解析

本题选C。

为了使处理时间最短,系统连续处理数据块。

本题中,T=100,M=5,C=90,n=2,代入 公式 得在单缓冲区读入并分析完该文件的时间是300。

设备分配与回收

Info

设备分配的任务是按照一定的策略,为提出I/O请求的进程分配合适的设备,确保CPU与I/O设备之间能正常通信,还应分配相应的控制器和通道。分配的总原则是充分发挥设备的使用效率,尽可能地让设备忙碌,又要避免由于不合理的分配方法造成进程死锁。

通道是一种独立于CPU的专用于I/O控制的处理器,它可以控制IO设备与内存直接进行数据交换。通道的启动需要由CPU执行相应指令,并在操作结束时向CPU发出中断信号。在数据交换过程中,CPU无需进行干预,可以提高CPU和IO的并行程度。

设备分配时应考虑的因素

  1. 设备的固有属性

  2. 独占设备:一个时段只能分配给一个进程(如打印机),设备利用率低。

  3. 共享设备:一段时间内可同时分配给多个进程使用(如磁盘),各进程往往是宏观上同时共享使用设备,而微观上交替使用。因此要注意对这些进程访问该设备的先后次序进行合理的调度.(一般采用动态分配方式,通过分时共享提高设备利用率)
“共享设备是一段时间内可同时访问,而不是同一时间;共享设备必须是可寻址和可随机访问的设备”如何理解?

“一段时间内可同时访问,而不是同一时间”这句话描述了宏观上并行与微观上串行执行的概念,这是理解操作系统如何管理并发任务的关键。

  • 宏观上的“同时访问”:对于多个进程(比如进程A、B、C)而言,它们都可以向同一个共享设备(如硬盘)发出读写请求,并且这些请求似乎是“同时”被处理的。从用户或进程的角度看,进程A不必等待进程B完全结束对硬盘的访问后才能开始自己的访问。在整个时间段(比如几秒钟)内,多个进程都使用了该设备,这就是“一段时间内可同时访问”。这得益于操作系统的并发处理能力。
  • 微观上的“不是同一时间”:物理上,一个像硬盘这样的设备,其磁头在同一个物理瞬间只能在一个位置读取数据。它不能在完全相同的时刻既为进程A读取文件X,又为进程B读取文件Y。操作系统接收到来自多个进程的I/O请求后,会将这些请求放入一个队列。然后,通过高效的调度算法(如电梯算法),快速地在这些请求之间切换执行。例如,磁头先为A服务(读取一小块数据),然后迅速移动为B服务(读取另一块数据),再回来为A服务。因为这个切换速度非常快(毫秒甚至微秒级别),所以给用户的感觉是“同时”在进行。

共享设备(如磁盘)的访问模式就是如此,操作系统通过快速调度和切换,让多个进程的I/O请求交织执行,实现了并发访问。

“共享设备必须是可寻址和可随机访问的设备”

  • 可寻址 :这意味着设备上的存储空间被划分成许多独立的、可唯一标识的单元(例如,硬盘的扇区或块)。每个单元都有一个唯一的地址。当操作系统或进程需要读写数据时,它可以精确地指定要操作的是“哪一个”单元。就像一本书的每一页都有页码,你可以直接翻到第58页,而不需要从第一页开始读。
  • 可随机访问 :这意味着访问设备上任何一个地址单元所需的时间,与该单元的物理位置无关,或者说差别不大。可以直接跳转到任意指定地址进行读写,而不需要按顺序从头开始。硬盘就是典型的随机访问设备,磁头可以直接移动(寻道)到任何磁道和扇区。

为什么这两个特性对共享至关重要?

因为操作系统需要高效地在多个进程的I/O请求之间来回切换。

  1. 可寻址是切换的基础。如果进程A要读地址为1000的数据,进程B要读地址为50000的数据。正因为地址是明确的,操作系统才能在为A服务后,清晰地知道下一个目标是地址50000,从而指导设备(如移动磁头)到正确的位置为B服务。
  2. 可随机访问保证了切换的效率。如果设备是顺序访问的(如磁带),要读取末尾的数据,必须先卷过前面的所有磁带。假如进程A请求磁带开头的数据,而进程B请求末尾的数据,那么为B服务一次的成本会非常高(需要等待磁带走到最后)。这种低效的切换使得“共享”失去了实际意义。因此,像磁带机这样的顺序存取设备通常被当作独占设备来使用。
  • 虚拟设备:采用 SPOOLing 技术将独占设备改造成虚拟的共享设备,可同时分配给多个进程使用(如采用SPOOLing技术实现的共享打印机)

  • 设备的分配算法

对设备分配的算法通常只采用先来先服务或优先级高者优先分配算法;

  1. 设备分配中的安全性

  2. 安全分配方式:为进程分配一个设备后就将进程阻塞,本次I/O完成后才将进程唤醒。(eg:考虑进程请求打印机打印输出的例子) 一个时段内每个进程只能使用一个设备  

  3. 优点:破坏了“请求和保持”条件,不会死锁  
  4. 缺点:对于一个进程来说,CPU和I/O设备只能串行工作
  5. 不安全分配方式:进程发出I/O请求后,系统为其分配I/O设备,进程可继续执行,之后还可以发出新的I/O请求。只有某个I/O请求得不到满足时才将进程阻塞。 一个进程可以同时使用多个设备
  6. 优点:进程的计算任务和I/O任务可以并行处理,使进程迅速推进  
  7. 缺点:由于可能具备“请求并保持“条件,因此可能发生死锁(解决方法:死锁避免、死锁的检测和解除)

  8. 设备分配方式

  9. 静态分配:进程运行前为其分配全部所需资源(即一次性分配该进程需要的全部设备、控制器和通道),运行结束后归还资源。破坏了“请求和保持”条件,不会发生死锁。主要用于独占设备的分配;

  10. 动态分配:进程运行过程中动态申请设备资源。有利于提高设备利用率,但是有死锁的可能;

设备分配管理中的数据结构

1760289722936-2a5225db-33be-405d-80d0-a4e511b0cfda.png

Info

一个设备控制器供多个同类设备共享使用,一个通道供多个设备控制器共享使用

  1. 系统设备表(System Device Table,SDT):一个系统一张,记录了已连接到系统中全部设备的情况,每个设备对应一个表目。每个表目存有 DCT(设备控制表)的指针,以及设备类型(即逻辑设备名)等1760288623384-ebede237-6dfe-4652-88fa-d7f926a36064.png
  2. 设备分配表(Device Control Table,DCT):系统为每个设备配置一张DCT,用于记录设备的各个属性.

1760287786614-d50ac712-0b2c-4316-86a3-96d7e2b92bca.png

  1. 控制器控制表(Controller Control Table,COCT):每个设备控制器都会对应一张COCT。操作系统根据COCT的信息对控制器进行操作和管理。

1760288987618-0903cb39-4d61-4732-8496-a05a8e212ff6.png

  1. 通道控制表(Channel Control Table,CHCT):每个通道都会对应一张CHCT。操作,系统根据CHCT的信息对通道进行操作和管理。

1760289083266-62da91e2-ff00-40ec-9f68-f3c2a66907df.png


设备分配的步骤

1760291667106-a714f5b8-464d-4ece-832e-0874fa5b6769.png

  1. 分配设备:根据进程请求的物理设备名查找SDT(用户在编程时需要用物理设备名作为系统调用的参数),根据SDT找到相应设备的DCT,根据其状态字段判断设备是否忙碌,若设备忙碌,则将进程PCB挂到设备等待队列中,不忙碌则将设备分配给进程。
  2. 分配控制器:设备分配给进程后,根据DCT找到COCT,若控制器忙碌则将进程PCB挂到控制器等待队列中,不忙碌则将控制器分配给进程。
  3. 分配通道:控制器分配给进程后,根据COCT找到CHCT,若通道忙碌则将进程PCB挂到通道等待队列中,不忙碌则将通道分配给进程。

Info

请求流程与设备的数据结构一致,即SDT→DCT→COCT→CHCT

【注】:只有设备、控制器、通道三者都分配成功时,这次设备分配才算成功,之后便可启动I/O设备进行数据传送

分析一下该分配方式的缺点:

①用户编程时必须使用“物理设备名”,底层细节对用户不透明,不方便编程

②若换了一个物理设备,则程序无法运行(即使有同类型的设备都不行)

③若进程请求的物理设备正在忙碌,则即使系统中还有同类型的设备,进程也必须阻塞等待

因此引入设备独立性

定义:又称设备无关性,是指应用程序与具体使用的物理设备无关,用户可以利用逻辑设备进行 IO 操作,不必指定物理设备。

优点:应用程序与具体使用的物理设备无关,系统增加或变更设备时不需要修改源程序,便于处理 I/O 设备故障,提升系统可靠性,并使设备的分配更加灵活,提升设备的利用率。

so 改进方法:建立逻辑设备名与物理设备名的映射机制,用户编程时只需提供逻辑设备名

实现该映射机制的好处:提高设备分配的灵活性和设备的利用率,方便实现I/O重定向,引入了设备独立性(指应用程序独立于具体使用的物理设备)。

改进之后,在应用程序中使用 逻辑设备名 来请求使用某类设备!!!


用逻辑设备分配的方案

根据进程请求的逻辑设备名查找 SDT,在 SDT 中每个表目里有一个字段记录了设备类型,因此操作系统可以根据用户提供的逻辑设备名依次查找 SDT,找到一个用户指定类型并且空闲的设备分配给该进程,只有所有该类型的设备都忙碌时才需要阻塞该进程。


逻辑设备表(Logical Unit Table,LUT):每个表项为<逻辑设备名,物理设备名,设备驱动程序入口地址>

【注】:

  1. 当进程首次请求设备分配时,系统为其分配一台相应的物理设备,同时在LUT中新增一个表项;
  2. 以后如果该用户进程再次通过相同的逻辑设备名请求使用设备,则直接查表即可;

LUT的建立方式:

  • 整个系统只有一张LUT:各用户所用的逻辑设备名不允许重复,适用于单用户操作系统
  • 每个用户一张LUT:存入用户进程的PCB中,不同用户的逻辑设备名可重复,适用于多用户操作系统

1760327725274-0372a687-1810-4f5c-bfd1-970d69b6655e.png

可类比文件系统中的单级目录和多级目录结构的区别,前者全部文件位于同一级别目录,因此不允许重名;后者允许不同级目录可以重名;

Info

在许多现代操作系统(如Linux)中,一个基础且优雅的设计哲学是“一切皆文件” (Everything is a file)。这意味着,几乎所有的系统资源,不仅仅是普通数据文件,还包括硬件设备、进程间通信等,都被抽象成文件的形式,并提供统一的接口进行访问。

对设备的“文件化”封装主要包括:

  • 命名与标识:每个设备在文件系统中都有一个对应的“设备文件”,通常位于 /dev 目录下。例如:
  • /dev/sda1 代表第一块硬盘的第一个分区。
  • /dev/tty1 代表一个物理终端。
  • 操作的映射:对硬件的复杂操作被巧妙地映射为我们所熟悉的文件I/O操作:
  • 打开设备:对应 open() 一个设备文件。
  • 从设备读取数据:对应 read() 设备文件(例如,从麦克风读取音频流)。
  • 向设备写入数据:对应 write() 设备文件(例如,向扬声器写入音频流)。

这种设计的优势显而易见:程序员无需为每一种新设备学习一套新的API。他们可以使用同一套文件操作函数来处理文件和设备,极大地简化了编程模型,并使得我们可以用 cat、dd 等标准命令行工具直接与硬件设备交互。

【2009-32】程序员利用系统调用打开I/O设备时,通常使用的设备标识是( )。

A. 逻辑设备

B. 物理设备

C. 主设备号

D. 从设备号

解析

在现代操作系统中,为了简化编程、提高系统可移植性和安全性,硬件设备被抽象化处理。程序员面向的是一个统一、简洁的接口,而不是种类繁多、细节各异的物理硬件。这种提供给程序员的抽象层接口,就是“逻辑设备”。

  1. 逻辑设备 (Logical Device): 这是对物理设备的抽象表示。在类UNIX系统(如Linux)中,所有设备都被抽象为文件。程序员通过操作这些设备文件(例如 /dev/sda1 代表第一个硬盘分区,/dev/ttyS0 代表串行端口)来间接访问硬件。这些路径和文件名就是逻辑设备名,程序员在代码中通过 open()这类系统调用,传入的正是这些逻辑设备名。
  2. 物理设备 (Physical Device): 这是指实际存在的硬件,如一块特定的硬盘、一个显卡或一个网卡。程序员通常不直接与物理设备交互,也无需关心其物理地址或内部电路。直接操作物理设备会使程序变得极其复杂,且与特定硬件绑定,无法在其他机器上运行。

程序员在利用系统调用(如 open())打开I/O设备时,传入的参数是操作系统提供的一个抽象标识,即逻辑设备名。这个名称为程序员屏蔽了底层硬件的复杂细节,使得程序开发更为高效和通用。

例如,当一个程序员想要读取硬盘数据时,他会在代码中打开一个类似 /dev/sda 或 C: 的逻辑设备,而无需关心这块硬盘的具体型号、接口类型或其在主板上的物理位置。同样,当执行打印操作时,程序会向一个名为“HP LaserJet Pro M404n”的打印机(这是一个逻辑设备名)发送数据,操作系统会通过其驱动程序将这个请求转化为对具体物理打印机的操作。

因此,正确答案是 A. 逻辑设备。这种抽象机制是现代操作系统设计的基石,它将应用程序员与硬件细节解耦,大大提升了软件开发的效率和可移植性。

区分主从设备 与主从设备号

简单来说:

  • 主从设备 (Master/Slave Device):这是硬件层面的概念,描述的是设备在总线上的控制权和通信角色。
  • 主从设备号 (Major/Minor Number):这是操作系统内核层面的概念,是操作系统用来标识和管理设备的一种编号机制。

1. 主从设备 (Master/Slave Device)

这个概念描述的是硬件设备在共享总线(连接CPU、内存、外设等的公共通道)上如何通信。

  • 领域: 硬件架构、总线协议。
  • 核心关系:谁发起,谁响应。
  • 主设备 (Master):
    • 角色: 主动方、发起者。
    • 能力: 可以获得总线的控制权,主动发起数据传输请求(读/写)。
    • 例子: CPU、DMA控制器。CPU想读取内存数据,它就是主设备;DMA控制器要将数据从硬盘搬到内存,它也是主设备。
  • 从设备 (Slave):
    • 角色: 被动方、响应者。
    • 能力: 不能主动发起传输,只能被动地响应主设备的寻址和读写命令。
    • 例子: 内存、大多数I/O接口芯片(如串口、并口)。它们只是等待被CPU或其他主设备访问。

一句话总结:在一次数据传输中,谁是老大(发起者),谁就是主设备;谁是被动的小弟(响应者),谁就是从设备。这个角色在不同的时间点是可以变化的。


2. 主从设备号 (Major/Minor Device Number)

这个概念是操作系统(特别是Unix/Linux系统)为了管理众多设备而设计的一种内部标识方案。

  • 领域: 操作系统内核、设备驱动程序。
  • 核心关系:对设备进行分类和编号。
  • 主设备号 (Major Number):
    • 作用:标识设备类型,或者更准确地说,是标识管理这类设备的驱动程序 (Driver)。
    • 特点: 同一类型、使用相同驱动程序的设备,其主设备号是相同的。
    • 例子: 系统中所有的SATA硬盘可能都共享同一个主设备号,因为它们都由同一个SATA驱动程序来管理。
  • 从设备号 (Minor Number):
    • 作用:标识具体的某个设备实例。
    • 特点: 在主设备号相同的情况下,用从设备号来区分不同的物理设备。
    • 例子: 您的第一块硬盘 (/dev/sda) 和第二块硬盘 (/dev/sdb) 会有相同的主设备号(因为都是SATA硬盘),但会有不同的从设备号(一个是0,一个是1),以便内核区分。

一句话总结:主设备号是给设备“分类”(这个设备归哪个驱动管),从设备号是给设备“编号”(你是这个驱动管辖下的第几个设备)。这是一个静态的、由操作系统分配的标识符。

【2023-32】下列因素中,设备分配需要考虑的是( )。

Ⅰ. 设备的类型

Ⅱ. 设备的访问权限

Ⅲ. 设备的占用状态

Ⅳ. 逻辑设备与物理设备的映射关系

A. Ⅰ、Ⅱ

B. Ⅱ、Ⅲ

C. Ⅲ、Ⅳ

D. Ⅰ、Ⅱ、Ⅲ、Ⅳ

解析

正确答案:D

本题考查的是操作系统中设备管理的核心职能——设备分配。设备分配是操作系统I/O子系统为了响应进程的I/O请求,而将物理设备资源分配给它的过程。这个过程必须周全地考虑多个因素,以确保系统的高效、安全、有序运行。

Ⅰ. 设备的类型

这是设备分配的策略基础。操作系统必须首先识别设备类型,因为不同类型的设备其分配方式和管理策略截然不同。

  • 按共享属性区分:
    • 独占设备 (Exclusive Device): 如打印机、扫描仪。在任意时刻只允许一个进程访问。操作系统需要为它们建立请求队列,实现互斥分配。
    • 共享设备 (Shared Device): 如磁盘。允许多个进程同时访问(宏观上并行,微观上串行)。操作系统需要通过调度算法(如磁盘调度算法)来优化访问顺序,提高效率。
  • 按数据传输方式区分:
    • 块设备 (Block Device): 如磁盘、U盘。以数据块为单位进行读写,支持随机访问。
    • 字符设备 (Character Device): 如键盘、鼠标、串口。以字符为单位进行I/O,通常是不可寻址的。

因此,不考虑设备类型,分配无从谈起。

Ⅱ. 设备的访问权限

这是设备分配的安全保障。操作系统作为系统资源的管理者,必须实施保护机制,防止未经授权的访问破坏系统。

  • 设备也被视为一种系统资源,操作系统会检查发起I/O请求的进程是否有权访问该设备。
  • 例如,在Linux系统中,设备被抽象为 /dev 目录下的文件。这些文件拥有与普通文件一样的权限位(读、写、执行),操作系统通过检查用户和进程的权限,来决定是否允许其 open() 这个设备文件。一个普通用户进程不应被允许直接访问原始磁盘分区,否则可能破坏整个文件系统。

Ⅲ. 设备的占用状态

这是设备分配的基本前提。在分配任何资源之前,必须先确认其当前是否可用。

  • 操作系统内部维护着一张设备状态表 (Device Status Table),记录了系统中每个设备的状态,如“空闲”或“忙碌”。
  • 当一个进程请求设备时,系统会查询此表。如果设备“空闲”,则可以分配给该进程,并将其状态置为“忙碌”。如果设备“忙碌”,则通常会将该请求进程放入对应设备的等待队列中,使其进入阻塞状态,直到设备被释放。

Ⅳ. 逻辑设备与物理设备的映射关系

这是实现设备无关性 (Device Independence) 的关键。设备无关性意味着应用程序在编写时无需关心自己使用的是哪个具体的物理设备,而是面向一个抽象的“逻辑设备”。

  • 应用程序发出的是对逻辑设备的请求(例如,请求“打印”到默认打印机)。
  • 设备分配的一个核心任务,就是将这个逻辑设备请求映射到一个当前空闲且合适的物理设备上。操作系统通过维护逻辑设备表 (LUT, Logical Unit Table) 等数据结构来完成这种映射。
  • 这样做的好处是极大地提高了软件的可移植性和系统的灵活性。例如,当一台物理打印机损坏时,系统管理员只需修改映射关系,将逻辑“打印机”指向另一台好的物理打印机,而无需修改任何应用程序代码。

结论:综上所述,设备的类型决定了分配策略,访问权限确保了分配的安全性,占用状态是分配的前提条件,而逻辑与物理设备的映射则是实现设备无关性、提高系统灵活性的核心手段。这四个因素都是设备分配过程中缺一不可的关键环节。因此,全部四项都需要考虑。

【2020-30】对于具备设备独立性的系统,下列叙述中,错误的是( )。

A. 可以使用文件名访问物理设备

B. 用户程序使用逻辑设备名访问物理设备

C. 需要建立逻辑设备与物理设备之间的映射关系

D. 更换物理设备后必须修改访问该设备的应用程序

解析

正确答案:D

设备独立性,也称为设备无关性,核心概念定义:

设备独立性是指应用程序在编写时应与具体使用的物理设备相分离。程序中使用的是抽象的逻辑设备名来请求 I/O 操作,而不是直接使用与硬件相关的物理设备名。操作系统负责完成从逻辑设备到物理设备的映射和转换。这样做的最大好处是增强了程序的可移植性和系统的灵活性。

A. 可以使用文件名访问物理设备

正确。 这是实现设备独立性的一种主流方式,尤其是在 Unix/Linux 系统中。操作系统将所有硬件设备(如硬盘、终端、打印机)抽象为特殊的文件,并存放在 /dev 目录下。应用程序就可以像读写普通文件一样,通过统一的文件名(一种逻辑设备名)和标准的 read()、write() 系统调用来访问这些设备,而无需关心设备的物理细节。

B. 用户程序使用逻辑设备名访问物理设备

正确。 这正是设备独立性的基本表现形式。用户程序请求 I/O 时,指定的是一个逻辑名称,如 “printer”、“console” 或 /dev/sda1。这个逻辑名称对用户和应用程序是有意义的,但它不是一个具体的硬件地址或型号。

C. 需要建立逻辑设备与物理设备之间的映射关系

正确。 这是实现设备独立性的内部核心机制。既然应用程序使用的是逻辑设备名,那么操作系统内部必须有一套机制来“翻译”这个请求。系统内部维护着一张或多张映射表(如逻辑设备表 LUT),记录了哪个逻辑设备名对应着当前系统中的哪个物理设备(以及其驱动程序)。当用户请求访问逻辑设备时,操作系统通过查表找到对应的物理设备,并调用其驱动来完成实际操作。

D. 更换物理设备后必须修改访问该设备的应用程序

此叙述错误。 这句话描述的情况恰恰是设备独立性所要解决和避免的问题。

  • 设备独立性的最终目的,就是为了让硬件的变更不影响上层软件。
  • 举例说明: 假设办公室的打印机从 A 型号(物理设备1)更换为 B 型号(物理设备2)。在一个具备设备独立性的系统中,系统管理员只需要更新操作系统层面的驱动,并修改逻辑设备“printer”到物理设备 B 的映射关系即可。
  • 对于用户的应用程序(如 Word、PDF 阅读器)而言,它们仍然是向逻辑设备“printer”发送打印请求,代码无需任何修改,甚至用户都感觉不到后台硬件发生了变化。
  • 如果更换设备后需要修改应用程序,那就意味着程序与特定硬件“耦合”了,这正是没有实现设备独立性的表现。

结论:设备独立性通过逻辑设备名和OS内部映射这两个关键手段,将应用程序与物理硬件解耦。因此,更换物理设备只需要修改OS层面的配置,而不需要修改应用程序。选项D的描述与设备独立性的根本目标背道而驰,故为错误叙述。

【模拟题】

  1. 在支持设备独立性的操作系统中,当一个进程首次通过逻辑设备名 printer1 请求使用打印机时,操作系统进行了一系列处理。如果在该进程的生命周期内,它再次使用逻辑设备名 printer1 发出I/O请求,此时操作系统最可能执行的操作是( )。

A. 再次遍历系统设备表(SDT),查找一台空闲的物理打印机

B. 直接查询该进程PCB中的逻辑设备表(LUT),找到之前绑定的物理设备

C. 检查设备控制表(DCT),确认物理设备状态后直接启动

D. 向通道控制表(CHCT)发出指令,准备数据传输

解析

正确答案:B

为了实现设备独立性,系统会建立逻辑设备表(LUT)来记录逻辑设备名到物理设备名的映射。

“当进程首次请求设备分配时,系统为其分配一台相应的物理设备,同时在LUT中新增一个表项”;“以后如果该用户进程再次通过相同的逻辑设备名请求使用设备,则直接查表即可”。

  • 在多用户操作系统中,通常是为每个用户(或进程)建立一张LUT,存放在其PCB中。因此,当进程第二次用同一个逻辑设备名请求时,系统最高效的方式是直接查找该进程自己的LUT,获取已建立的映射关系。
  • A选项是首次分配时的操作。C和D选项是找到了物理设备之后,准备启动I/O的具体步骤,而不是查找设备的步骤。因此,B选项最准确地描述了再次请求时的核心操作。
  1. 某操作系统采用静态分配方式管理设备资源,并且为多用户环境。关于该分配方式,下列叙述中,错误的是( )。

A. 该方式可以有效避免进程因竞争设备而产生的死锁

B. 在为进程分配资源时,主要依据的是进程声明的资源需求

C. 进程一旦开始运行,其占有的设备资源不会被其他进程抢占

D. 相比动态分配,该方式通常能带来更高的设备利用率

解析

正确答案:D

  • 静态分配是在进程运行前将其所需的全部资源一次性分配到位。这种方式破坏了死锁产生的四个必要条件之一的“请求和保持”条件,因此可以避免死锁。所以A正确。
  • 既然是运行前分配,那分配的依据自然是进程预先声明它需要哪些资源。所以B正确。
  • 静态分配是一种非抢占式的分配,资源一旦分配给某进程,只有在该进程运行结束或主动释放后才能被收回。所以C正确。
  • 静态分配的主要缺点在于,进程可能在很长一段时间内并不使用某些已分配给它的设备,而其他进程又无法使用这些设备,从而导致设备利用率降低。因此,“能带来更高的设备利用率”的说法是错误的,这通常是动态分配的优点。所以D错误。

假脱机(SPOOLing)技术

1757493445964-141c3d21-0e22-4b61-adeb-8e829e00d36c.png

为了后续讲解简化后的模型

上图是未引入 SPOOLing 技术之前的打印机执行打印任务的大致流程,它有以下弊端

弊端一:CPU 资源被独占,效率极低

这是最致命的缺点。如图所示,CPU需要亲自处理每一次的数据“搬运”:从内存读数据 -> 写入寄存器 -> 从寄存器写到I/O端口。打印机是非常慢的设备,CPU每发送一小块数据,就可能需要停下来查询控制器的状态,看它是否准备好接收下一块数据(这个查询过程本身也要消耗CPU)。这意味着,在整个漫长的打印过程中,CPU的大部分时间都耗费在等待和搬运数据上,而不是去执行更有价值的计算任务。CPU的强大算力被严重浪费了。

弊端二:用户进程长时间阻塞

由于CPU需要全程伺服这个打印过程,那么发起打印请求的用户进程P1就会被阻塞(Blocked)。在打印任务没有彻底完成之前,P1无法被唤醒,也不能继续执行它后面的任何代码。如果需要打印一份几十页的文档,P1可能要被“冻结”几分钟甚至更久。

弊端三:计算与I/O无法并行

这种方式决定了对于同一个进程来说,计算和I/O操作是严格串行的。要么进程在进行计算,要么进程在等待I/O,二者不能同时发生。这大大降低了单个程序的执行效率。

弊端四:系统整体吞吐量低

由于CPU被一个慢速的I/O任务长时间占用,其他需要CPU进行计算的进程也必须等待,导致整个系统的任务处理能力(吞吐量)非常低下。

1757494695196-55c80d9c-6011-4601-80c4-771a0c3e8187.png

引入SPOOLing技术带来的优点:

1. 提高了用户进程的响应速度(实现了“虚拟”高速打印)

“一旦数据被拷贝到‘输出缓冲区’,并由井管理程序接管,用户进程的任务就算完成了。它可以立即返回,继续执行后续的计算任务,而无需等待慢长的打印。”对于用户进程P1而言,它感觉到的不是在跟一台慢速打印机打交道,而是在跟一块高速的磁盘打交道。它只需要把数据快速地“甩”到输出井,打印任务就(在它看来)“瞬间”完成了。这种将慢速设备“伪装”成高速设备的技术,我们称之为设备虚拟化。

2. 缓和了CPU与慢速I/O设备的速度矛盾,极大提高了CPU利用率

在没有SPOOLing的老方法中,高速的CPU必须全程迁就慢速的打印机,导致CPU大量时间处于空闲等待状态。

引入SPOOLing后,CPU只参与两次高速的数据传输:

  • 第一次:从P1用户空间拷贝到内核缓冲区1(内存 -> 内存,极快)。
  • 第二次:“井管理程序”将数据从缓冲区1写入磁盘输出井(内存 -> 磁盘,很快)。

完成这两步后,CPU就被完全解放出来,可以立即去为其他进程服务。而真正耗时的“从磁盘井到打印机”的过程,则交由独立的“输出进程”去处理,它可以在CPU空闲时见缝插针地运行,或者通过DMA(直接内存访问)方式进行,进一步减少对CPU的打扰。

3. 实现了计算与I/O操作的真正并行

这是SPOOLing技术名字(Simultaneous Peripheral Operations On-Line,外部设备联机并行操作)的精髓。在一个引入了完整SPOOLing系统的计算机中,可以出现这样的高效场景:

  • CPU 正在全力执行进程B的计算任务。
  • 输出进程 正在将磁盘井中进程A的打印数据送往打印机。
  • 输入进程 正在从读卡器读取数据,为进程C准备输入数据并存入输入井。

输入、计算、输出,这三件事情可以在宏观上同时进行,互不干扰。这使得整个系统的各个部件都能“忙”起来,而不是像老方法那样,一个部件工作,其他部件都干等着。

4. 提高了系统的吞吐量

综合以上优点,CPU的利用率大大提高,进程不再因为I/O而长时间阻塞,各项工作得以并行处理。最终的结果就是,整个计算机系统在单位时间内能够完成的总任务量(即系统吞吐量)得到了质的飞跃。

总而言之,SPOOLing技术,通过“ 用磁盘空间换取时间”和“增加专门的I/O进程” 这两种策略,成功地将原本串行、阻塞、低效的I/O模式,改造成了并行、高效的模式,是操作系统发展史上的一个里程碑式的进步。

1757518949483-2d72a77a-5c00-4c8d-80a0-9e57e333bbca.png

上图展示了SPOOLing系统如何优雅地解决“多个进程抢占一台打印机”的问题。

  1. 井管理程序接手打印任务

如图左侧所示,操作系统中可能同时运行着多个进程(P1, P2, P3, P4),它们在各自的执行过程中,都可能在不同的时间点发出了打印请求。对于每个发出请求的进程,操作系统会将其数据从用户空间拷贝到内核的“输出缓冲区1”,然后由“井管理程序”接管。

可以看出系统很快地处理完P1的请求(只是把数据甩给井管理程序),然后立刻去响应P2的请求,接着是P3... 每个进程都不会因为打印机“正忙”而被长时间阻塞。它们都会感觉自己的打印请求被“立即”受理了。 (未经 SPOOLing 改造的打印机,当 P1 进程使用打印机时,其他进程请求打印机的时候就会被阻塞,更别提后面还会因为需要等待 I/O 完成而阻塞)

  1. 在输出井中形成队列

如图中间部分,“井管理程序”是这里的“交通调度员”。它接收到来自不同进程的打印数据后,并不会混在一起,而是将它们作为独立的打印作业(Job),一个接一个地存放到磁盘的“输出井”中。为了管理这些作业,井管理程序会为每个作业记录管理信息,比如:这个作业属于哪个进程(P1还是P2)、数据在磁盘上的存放位置、数据大小、请求的先后顺序等。

这样,就在高速磁盘上形成了一个打印任务队列。这个队列忠实地记录了所有待处理的打印任务,等待独占设备——打印机的处理。

  1. 输出进程按序处理

如图右侧所示,独立的“输出进程”是这个队列的唯一消费者。它就像一个专职的打印员。它会根据预设的调度策略(通常是先进先出 FCFS),从“输出井”的队列头部取出一个作业(比如,先处理作业1,即P1的数据)。

输出进程将该作业的数据从磁盘读入内存的“输出缓冲区2”,然后慢慢地、完整地将它输出到打印机。

在输出进程打印作业1的过程中,其他进程(如P5, P6)仍然可以继续提交新的打印请求到输出井的队尾。打印机的慢速输出过程与新请求的快速接收过程,完全实现了并行。

当作业1打印完毕后,输出进程会从井中取出下一个作业(作业2),重复上述过程,直到整个打印队列为空。

由此可见 SPOOLing技术的以下核心优点:

Info

  • 实现了对独占设备的虚拟化:对于每个进程来说,它们仿佛各自都拥有一个打印机,可以随时提交打印请求,而无需关心物理打印机是否正忙。SPOOLing系统为它们提供了这种“虚拟设备”的假象。(将独占设备改造为共享设备)
  • 有序管理:通过在磁盘上建立队列,SPOOLing系统将并发、无序的打印请求,转换成了有序、串行的物理打印操作,避免了不同进程的输出内容混杂在一起。
  • 提高了系统整体效率:极大地减少了进程因等待I/O设备而阻塞的时间,使得CPU能够更高效地在多个进程之间切换运行,从而提高了整个系统的并发能力和吞吐量。

SPOOLing技术改造输入设备

1757524709040-c67f8223-f19f-44c4-a02c-b22844c97029.png

弊端:首先输入设备被单个进程独占,假设 P1 进程申请到了输入设备,其他需要该设备输入数据的进程的就会因为设备忙碌申请不到而阻塞;其次,如果输入设备很慢,进程 P1 需要等待数据全部输入以后才能执行,这会让进程 P1 的执行完成时间大幅度提高;最后,在系统调用服务程序将数据从内核缓冲区复制到用户空间,一直到进程 P1 释放该设备这段时间内,慢速的输入设备处于空闲状态,本来就干的慢,还让它休息;

简化模型

1757527495701-4690a028-b41f-4b89-8109-d345b3caf9f3.png

Info

SPOOLing 是用软件的方式,建立在通道技术和多道程序技术的基础上;(这也间接说明了多道程序技术提高了I/O设备的利用率)

目的:为了缓和高速CPU和低速IO之间的矛盾(向磁盘输出数据的速度比向IO设备输出数据的速度快)

优点:提高了I/O速度,将独占式设备虚拟成共享式设备,实现了虚拟设备(空间换时间),提高了独占设备(系统资源的利用率),加快了作业执行速度(将串行改成了并行);

条件:需要大容量,高速度的外存(通常为磁盘)作为输入输出井;需要多道程序技术的支持;

【2016-31】下列关于SPOOLing技术的叙述中,错误的是( )。

A. 需要外存的支持

B. 需要多道程序设计技术的支持

C. 可以让多个作业共享一台独占设备

D. 由用户作业控制设备与输入/输出井之间的数据传送

解析

正确答案:D

SPOOLing 技术核心工作原理

  1. 引入高速缓冲: 操作系统在高速的磁盘上开辟出专门的空间,分别称为“输入井”(Input Spool)和“输出井”(Output Spool)。
  2. I/O重定向: 当用户作业请求对某个独占设备(如打印机)进行输出时,操作系统并不会让作业直接与打印机交互。相反,它会拦截这个请求,并将作业要输出的数据高速地写入磁盘的“输出井”中。对于作业而言,这个写入过程极快,它会误以为打印已经完成,从而可以立即释放 CPU,让其他作业得以运行。
  3. 后台物理操作: 操作系统有一个专门的、独立运行的系统进程(称为 SPOOLing 守护进程或打印机守护进程),该进程会不断地检查“输出井”。一旦发现有待打印的数据,它就会按照一定的次序,将数据从输出井中取出,并慢速地传送给物理打印机进行实际打印。

整个过程对用户作业是透明的,它将一个物理上的独占设备虚拟成了多个逻辑上的、可供所有作业“同时”使用的设备。

选项分析

A. 需要外存的支持 (正确) 这是 SPOOLing 技术的基础。所谓的“输入井”和“输出井”就是建立在高速外存(磁盘)上的缓冲区。没有磁盘作为中转站,就无法实现数据的暂存和I/O重定向。

B. 需要多道程序设计技术的支持 (正确) SPOOLing 技术的价值正是在多道程序环境下体现的。当一个作业将其输出高速写入磁盘后,它就可以继续计算或结束,CPU 能够立即切换到另一个作业。与此同时,SPOOLing 守护进程作为另一个“程序”,在后台并行地处理物理打印任务。如果没有多道程序设计,CPU 在一个作业等待打印时就会闲置,SPOOLing 的优势便无从谈起。

C. 可以让多个作业共享一台独占设备 (正确) 这是 SPOOLing 技术最主要的目的和成果。例如,作业 A、B、C 都可以“同时”执行打印命令,它们的数据会被分别写入输出井的不同区域。SPOOLing 系统会自动形成一个打印队列,然后依次将这些作业的数据送往物理打印机。它成功地将一台一次只能为一个作业服务的“独占设备”,改造成了可被多个作业并发请求的“共享设备”。

D. 由用户作业控制设备与输入/输出井之间的数据传送 (错误) 这是对 SPOOLing 技术原理的根本性误解。SPOOLing 的核心特征之一就是对用户作业的透明性。用户作业只负责发出逻辑上的 I/O 请求(如“打印这个文件”),它并不知道、也完全不控制数据是如何被写入“井”中,以及后续是如何从“井”中传送到物理设备的。整个数据在中转区(输入/输出井)的管理和与物理设备间的实际传送,完全是由操作系统内核中的 SPOOLing 系统(守护进程)来统一管理和控制的。用户作业无法也无权干预这个过程。

结论: SPOOLing 技术是一种操作系统层面的 I/O 管理策略,对用户作业是透明的。用户作业仅发起逻辑I/O请求,而数据在“井”与物理设备之间的传送是由操作系统负责的,并非由用户作业直接控制。因此,D选项的叙述是错误的。

【模拟题 1】 在采用SPOOLing技术的操作系统中,当一个正在运行的用户进程P1请求打印输出时,操作系统为该请求所做的一系列动作中,第一步是( )。

A. 将打印机分配给进程P1

B. 在磁盘的输出井中为进程P1申请一块空闲区域

C. 将打印数据从P1的用户空间复制到内核的内存缓冲区

D. 启动独立的输出进程,准备从输出井读取数据

解析

正确答案是 C。

  • A (错误):SPOOLing技术正是为了避免将物理设备直接分配给某个用户进程。打印机由独立的“输出进程”统一管理,不会分配给特定的用户进程。
  • B (错误):为P1在输出井中申请空间是后续步骤,通常由“井管理程序”在接收到数据后完成,而不是处理用户请求的第一步。
  • C (正确):我们之前的所有图中都明确了这一点。用户进程发起系统调用后,操作系统响应的第一步,是为了安全和管理,将需要打印的数据从用户地址空间拷贝到操作系统内核所管理的内存缓冲区中。后续操作都是基于这个内核缓冲区的数据进行的。
  • D (错误):独立的输出进程负责将数据从“输出井”传送到打印机。它只在井中有数据且打印机空闲时才启动或工作,而不是在用户刚提交请求时就启动。

【模拟题 2】 关于SPOOLing技术带来的优势,下列叙述中错误的是( )。

A. 用户进程发出的I/O请求,其大部分等待时间发生在对磁盘“井”的读写上

B. 实现了CPU的计算任务与外设的I/O操作在宏观上的并行执行

C. 提高了系统的吞吐量和设备的利用率

D. 减少了用户进程因等待I/O完成而产生的阻塞时间

解析

正确答案是 A。

  • A (错误):SPOOLing技术的核心优势在于,用户进程发出的I/O请求,感觉上是与一个高速设备(磁盘井)在打交道。相对于与慢速物理设备交互的漫长等待时间(等待慢速设备 IO 完成),对磁盘“井”的读写速度非常快,因此等待时间极短。所以“大部分等待时间发生在对磁盘‘井’的读写上”这个说法是错误的,它恰恰是等待时间最短的部分。
  • B (正确):这是SPOOLing技术的定义性优势。CPU可以处理一个作业的计算,而输入/输出进程可以同时处理另一个作业的I/O,实现了宏观上的并行。
  • C (正确):由于实现了并行,CPU和I/O设备都能更“忙碌”,减少了空闲等待,因此系统单位时间内完成的任务量(吞吐量)和设备的利用率都得到了提升。
  • D (正确):用户进程只需将I/O请求提交给SPOOLing系统(即数据被拷贝到内核缓冲区,由井管理程序接管),就可以立即返回继续执行,无需等待慢速I/O的最终完成,因此其阻塞时间被极大缩短了。

【模拟题 3】 关于SPOOLing系统中的“输出进程”(即负责将数据从输出井传送到打印机的进程),下列叙述中正确的是( )。

A. 该进程由提交打印请求的用户作业所创建

B. 只有当输出井中存在待打印作业时,该进程才会被创建

C. 该进程直接从用户作业的地址空间读取待打印数据

D. 该进程由操作系统管理,负责执行对物理打印机的实际I/O操作

解析

正确答案是 D。

  • A (错误):“输出进程”是一个系统级的后台服务进程(或守护进程),它独立于任何用户作业,由操作系统在启动时创建和管理。
  • B (错误):该进程通常是常驻内存的,而不是按需创建。当井中没有任务时,它处于休眠或阻塞状态;当井中有新任务时,操作系统会唤醒它。
  • C (错误):用户作业的数据已经被转存到磁盘的“输出井”中。输出进程的数据来源是“输出井”,而不是任何用户作业的地址空间。
  • D (正确):这准确描述了“输出进程”的职责。它是一个系统进程,拥有执行底层I/O操作的权限,是SPOOLing系统中唯一直接与物理打印机硬件打交道的模块。

【模拟题 4】 SPOOLing技术通过将独占设备改造为共享设备,显著提升了系统效率。下列关于其工作原理的叙述中,错误的是( )。

A. 它利用了“以空间换时间”的思想,使用部分磁盘空间作为缓冲区

B. 它为每个用户进程提供了“虚拟设备”,使其可随时提交I/O请求

C. 其主要目标是缩短数据在I/O设备和内存之间的物理传输时间

D. 对“输入/输出井”中作业队列的管理,由操作系统负责

解析

正确答案是 C。

  • A (正确):SPOOLing技术本质上就是用相对廉价和海量的磁盘空间(空间)来换取宝贵的CPU等待时间(时间)。
  • B (正确):SPOOLing的核心功能之一就是设备虚拟化。对于用户进程而言,它感觉自己面对的是一个随时可用的“虚拟打印机”,而无需关心物理打印机是否正忙。
  • C (错误):这是一个非常关键的区分点。SPOOLing技术并不能改变物理设备本身的传输速度。打印机该有多慢还是多慢。它的主要目标是解放CPU,让CPU不必等待这个慢速的物理传输过程,从而去执行其他计算任务。它优化的是CPU的等待时间,而不是设备的物理传输时间。
  • D (正确):对井中队列的维护(如采用先来先服务策略、记录作业信息等)是操作系统的核心管理职能之一,对用户是透明的。

设备驱动程序的统一接口

对于某个外设具体的I/O操作,通常需要通过执行设备驱动程序来完成。而外设的种类繁多,控制接口不一致,导致不同外设的设备驱动程序千差万别。如果计算机系统中每次出现一种新的外设,都要为添加一种新设备驱动程序而修改操作系统,那么就会给操作系统开发者和系统用户带来很大的麻烦。

为此,操作系统为所有外设的设备驱动程序规定了一个统一的接口,新设备驱动程序只要按照统一的接口规范来编制,就可以在不修改操作系统的情况下,在系统中添加新设备驱动程序并使用新的外设进行I/O。

对于每种设备类型,例如磁盘,操作系统都要定义一组驱动程序必须支持的函数。对磁盘而言,这些函数自然包含读、写、格式化等。驱动程序中通常包含一张表格,这张表格具有针对这些函数指向驱动程序自身的指针。装载驱动程序时,操作系统记录这个函数指针表的地址,所以当操作系统需要调用一个函数时,它可以通过这张表格发出间接调用。这个函数指针表定义了驱动程序与操作系统其余部分之间的接口。给定类型的所有设备都必须服从这一要求。

1760342107318-68ce6aef-1192-4ee7-b6d7-a4fc896669d5.png

Info

工作流程: 当一个应用程序需要从三星SSD中读取数据时,操作系统内核的上层软件会发出一个通用的 read() 请求。内核根据这个请求是发往三星SSD的,就会去查找“三星SSD驱动的函数指针表”,看到标准 read() 接口对应的是 samsung_ssd_read() 这个具体函数的地址,然后内核就会间接调用samsung_ssd_read() 函数来完成实际的硬件操作。

因为采用了统一的设备驱动程序接口,因而,内核中与设备无关的I/O软件包含了所有外设统一的公共接口中的处理部分。为了简化对外设的处理,在内核高层I/O软件中,将所有外设都抽象成一个文件,设备名和文件名在形式上没有任何差别,因而被称为设备文件名。\ 内核中与设备无关的I/0软件必须将不同的设备名和文件名映射到对应的设备驱动程序。例如,在UNIX/Linux系统中,一个设备名将能够唯一地确定一个特殊文件的i节点。一个i节点中包含了主设备号,而主设备号可用于定位相应的设备驱动程序。i节点还包括次设备号,次设备号可作为参数传递给设备驱动程序,用来确定进行 I/O 操作的具体设备位置。

相关知识扩展

【注】:在UNIX/Linux系统中,除了普通文件和目录文件以外,还有一类特殊文件,包括设备文件、链接文件等,设备特殊文件包含块设备特殊文件和字符设备特殊文件等,前者主要用于磁盘类设备,后者主要用于各类输入/输出设备,如终端、打印机、网络等。i节点是一个固定长度的表,包含对应文件相关的各种信息,如文件大小、文件所有者、文件访问权限,以及文件是普通文件、目录文件还是特殊文件等,在i节点中最重要的一项是磁盘地址列表。特殊设备文件对应的i节点中包含主设备号和次设备号,主设备号确定设备类型(如USB设备、硬盘设备),因而它被系统用来确定设备驱动程序,次设备号被驱动程序用来确定具体的设备。

一个便于理解设备驱动程序统一接口的示例(学习自零壹遇见)

1760336836621-eed25cfa-10a9-4dbe-8779-b6c5fce7cf82.png

  1. 统一的设备驱动程序接口 (操作系统内核视角)

操作系统内核(或上层调用者)只关心这套标准接口,它不关心具体是哪台打印机以及如何实现。

// --- 这是操作系统规定的、所有打印机驱动都必须遵守的接口规范 ---
void initialize_printer();
void print_page(char* page_data, int size);
....
  1. 惠普打印机的驱动实现 (基于统一编址)驱动程序通过读写特定的内存地址来与其通信。
volatile char* data_buffer = (char*)0xF8001000;
volatile unsigned int* command_status_reg = (unsigned int*)0xF8000004;

// 初始化打印机
void initialize_printer() 
    *command_status_reg = 0xB1H; //// 向命令寄存器写入“初始化”命令字 B1H
    // 循环查询状态寄存器,直到打印机报告“准备就绪”
    while (*status_reg != READY_STATE);
}

void print_page(char* page_data, int size) {
    // 1. 查询状态,确保打印机处于“准备就绪”状态
    while (*command_status_reg != READY_STATE); // READY_STATE 是一个预定义的状态码

    // 2. 发送“接收页面数据”命令
    *command_status_reg = 0xB2H;

    // 3. 将整页数据拷贝到设备的页面数据缓冲区
    memcpy(data_buffer, page_data, size);

    // 4. 发出“执行打印”命令
    *command_status_reg = 0xB3H;

    // 5. (可选) 驱动程序可以继续轮询状态,直到打印完成
    while (*status_reg == PRINTING_STATE);
}
  1. 佳能打印机的驱动实现 (基于独立编址)
#define CONTROL_PORT 0x378
#define DATA_PORT    0x379

// 预定义的状态码
#define STATUS_READY 0x01
#define STATUS_BUSY  0x02

// 辅助函数,用于查询Brother打印机的状态
static unsigned char get_canon_status() {
    // 1. 先向控制端口发送“请求状态”的命令
    outb(0xD3H, CONTROL_PORT);
    // 2. 然后从同一个端口读回状态字节
    return inb(CONTROL_PORT);
}

// === 实现标准接口函数 ===

void initialize_printer() {
    // 向控制端口发送“初始化”命令 D0H
    outb(0xD0H, CONTROL_PORT);

    // 循环查询状态,直到打印机报告“准备就绪”
    while (get_canon_status() != STATUS_READY);
}

void print_page(char* page_data, int size) {
    // 1. 检查打印机是否就绪
    if (get_canon_status() != STATUS_READY) {
        return; // 或者进行错误处理
    }

    // 2. 发送“准备数据传输”命令 D1H
    outb(0xD1H, CONTROL_PORT);

    // 3. 关键区别:通过循环,将页面数据逐字节地发送到数据端口
    // 这与之前HP例子中直接内存拷贝(memcpy)的方式完全不同
    for (int i = 0; i < size; i++) {
        outb(page_data[i], DATA_PORT);
    }

    // 4. 数据发送完毕后,发出“开始打印作业”命令 D2H
    outb(0xD2H, CONTROL_PORT);
}
特性 HP 打印机 canon 打印机
I/O方式 统一编址 (内存映射) 独立编址 (端口I/O)
数据传输 memcpy到大块内存缓冲区 for循环逐字节写入数据端口
状态获取 直接读取状态寄存器内存地址 先发命令D3H,再从端口读状态
命令集 B系列命令 (B1H, B2H...) D系列命令 (D0H, D1H...)
提供给OS的接口 initialize_printer(), print_page() initialize_printer(), print_page()(二者完全相同)

Info

最终,操作系统的上层模块调用 print_page() 函数时,它完全不知道也不需要关心,数据是被 memcpy 到了一片内存,还是被一个循环一个字节一个字节地发送到了一个I/O端口。这就是设备驱动程序接口的强大之处:它将上层软件的调用意图与下层硬件的复杂实现彻底解耦。

Info

例题:对于设备驱动程序的描述,错误的是()

A、不同型号的同类设备提供给相同上层系统的接口可能不同。

B、同一型号的同类设备提供给不同上层系统的接口可能不同。

C、设备驱动程序可以直接访问 I/O 端口。

D、用户程序对设备的访问与设备自身的中断处理均使用设备驱动程序提供的接口。

解析

同一个操作系统对同类型的所有设备的驱动程序提出了统一的接口规范要求,因此不同型号的同类设备为同一个系统提供的接口是一样的,而不同系统提出的接口规范可能是不一样的,因此 A 错误,B 正确。C 选项,设备驱动程序正是通过对 I/O 端口的操作来实现对设备的访问,C正确。D 选项,用户对设备的访问依靠设备驱动程序提供的接口,设备的中断处理中也需要对设备进行检测和访问等,因此同样需要设备驱动程序的接口支持,D 正确。

操作系统为所有块设备(如硬盘、SSD)定义一个统一的设备驱动程序接口,其最主要的目标是( )。

A. 允许CPU更高效地直接访问设备的数据寄存器

B. 向上层软件(如文件系统)隐藏不同硬件设备的物理实现差异

C. 确保所有厂商的设备驱动程序都使用同一种编程语言编写

D. 简化操作系统内核处理硬件中断的流程

解析

正确答案:B

  • 设备驱动程序接口的核心设计哲学是抽象和封装。通过制定一套标准(如必须提供read_block, write_block等功能),操作系统内核的文件系统等上层软件可以用一种统一的方式来发出I/O请求,而无需关心底层硬件是机械硬盘还是SSD,它们的命令字、寻址方式有何不同。这正是设备独立性的体现。
  • A选项不正确,接口本身是一种软件抽象,可能会引入微小的间接调用开销,其目的不是为了提高访问效率。
  • C选项是错误的,接口是功能和调用约定上的规范,与具体编程语言无关。
  • D选项不全面,中断处理只是驱动程序功能的一部分,而接口的目的是统一所有I/O操作,范围更广。

设备驱动程序

  1. 设备驱动程序的功能

为了实现I/O系统高层与设备控制器之间的通信,设备驱动程序应具有以下功能:

  • 通信与转换:作为上层软件与硬件的桥梁,它接收来自设备无关性软件的抽象命令(如“读取第500号盘块”),并将其转换为设备控制器能理解的具体指令(如设定磁头、磁道、扇区号等)。同时,它将硬件返回的状态和结果报告给上层
  • 检查用户I/O请求的合法性,了解I/O设备的工作状态,传递与I/O设备操作有关的参数,设置设备的工作方式。
  • 发出I/O命令,如果设备空闲,便立即启动I/O设备,完成指定的I/O操作;如果设备忙碌,则将请求者的请求块挂在设备队列上等待(即将其阻塞)。

  • 设备驱动程序的特点

设备驱动程序属于低级的系统例程,它与一般的应用程序及系统程序之间有下述明显差异:

  • 硬件相关性:驱动程序与特定硬件的物理特性(如寄存器、指令集)紧密耦合,不同设备需要不同的驱动程序
  • 驱动程序与I/O设备所采用的I/O控制方式紧密相关,常用的I/O控制方式是中断驱动和DMA方式。
  • 由于驱动程序与硬件紧密相关,因而其中的一部分必须用汇编语言书写。目前有很多驱动程序的基本部分已经固化在ROM中。
  • 可重入性:驱动程序必须是可重入的,即在一次调用完成前,能够被另一个任务(如中断)再次安全调用。

设备驱动程序通常被设计为“可重入”的,这主要是为了解决下列哪一种情况可能导致的冲突?( )

A. 多个不同的用户进程同时通过系统调用,请求访问同一个设备

B. 在多核处理器上,两个CPU核心同时执行同一个驱动程序中的代码段

C. 一个进程在等待磁盘I/O时被阻塞,操作系统调度另一个进程也发起了对该磁盘的I/O请求

D. 驱动程序在响应系统调用处理I/O请求的过程中,被该设备完成上一次操作所产生的硬件中断所打断

解析

正确答案:D

  • A和C描述的是多进程访问的场景,这通常通过锁来保证互斥,属于线程安全问题,而非可重入问题。
  • B描述的是多核并行场景,通常通过自旋锁来保护临界区。
  • D选项描述的正是可重入性的经典场景:驱动程序的代码(如处理write系统调用的部分)正在执行时,一个硬件中断到来,导致CPU切换去执行该驱动程序的另一部分代码(中断服务程序)。如果这两部分代码使用了共享的全局或静态变量而没有特殊保护,就可能导致数据错乱。可重入函数通过不使用这类共享数据或有特殊保护,来保证在这种“自我打断再进入”的情况下依然能正确工作。
  1. 设备处理方式(可不看,不重要)

在不同的操作系统中,所采用的设备处理方式并不完全相同。根据在设备处理时是否设置进程,以及设置什么样的进程,而把设备处理方式分成以下三类:

  • 为每一类设备设置一个进程,专门用于执行这类设备的I/O操作。比如,为所有的交互式终端设置一个交互式终端进程;又如,为同一类型的打印机设置一个打印进程。这种方式比较适合于较大的系统。
  • 在整个系统中设置一个I/O进程,专门用于执行系统中所有各类设备的I/O操作。也可以设置一个输入进程和一个输出进程,分别处理系统中的输入或输出操作。
  • 不设置专门的设备处理进程,而只为各类设备设置相应的设备驱动程序,供用户或系统进程调用。这种方式目前用得较多。

  • 设备驱动程序的处理过程:当驱动程序接收到一个I/O请求后,通常会按以下步骤执行

  • 抽象请求到具体操作的转换:将上层软件发出的逻辑请求(如盘块号)翻译成硬件能识别的具体参数(如盘面号、磁道号、扇区号)。
  • 合法性与权限校验:检查用户请求的操作是否被允许,例如,一个以只读方式打开的设备不能执行写操作。
  • 设备状态检查:通过读取设备控制器的状态寄存器,确认设备当前是否处于可接收命令的就绪状态。
  • 参数设置与传送:向设备控制器的相应寄存器(如命令寄存器、数据寄存器、方式寄存器)写入执行本次任务所需的参数(如数据传输率、数据长度等)。
  • 启动设备与阻塞进程:向控制器发送启动命令。在中断或DMA模式下,驱动程序发出命令后便会放弃CPU,并将发起请求的进程阻塞,直到硬件完成任务并以中断方式通知CPU。这一机制实现了CPU与I/O设备的并行工作。

  • 对I/O设备的控制方式

重点设备驱动程序中包含了许多I/O指令,通过执行I/O指令,CPU可以访问设备控制器中的I/O端口,从而控制外设的I/O操作。 设备驱动程序与硬件的交互方式(即I/O控制方式)直接决定了其内部实现逻辑和对系统性能的影响。主要有以下三种控制方式:

  1. 程序直接 I/O方式

若采用程序I/O方式,设备驱动程序将全程、主动地控制I/O操作。

  • 处理过程:驱动程序向设备控制器发送命令后,会进入一个“忙等”循环,不断地查询设备状态寄存器,直到I/O操作完成。
  • CPU与外设关系:在此期间,CPU完全被I/O任务占用,无法执行其他任何进程。CPU与外设的I/O操作是完全串行的。
  • 进程状态:从操作系统的角度看,请求I/O的用户进程并未被置于“阻塞”状态并移出运行队列。但实际上,由于CPU被其I/O任务独占,该进程(以及整个系统中的其他进程)的执行流被事实性地暂停了,直到I/O结束。
  • 中断使用:这种方式不使用中断。(在这种情况下,驱动程序实际上就是一个查询程序,而且也不再调用中断服务程序)

  • 中断驱动I/O方式

若采用中断驱动I/O方式,驱动程序通过中断机制来避免CPU的忙等,实现CPU与外设的并行。

  • 处理过程:驱动程序向设备控制器发出I/O命令以启动第一次数据传输(例如,一个字节或一个字)后,它不会等待,而是立即放弃CPU。操作系统此时会调用处理器调度程序(scheduler),将CPU分配给其他就绪进程。
  • CPU与外设关系:发出I/O命令后,CPU可以执行其他进程,而外设同时进行数据传输,实现了CPU与I/O的并行。
  • 进程状态:发起I/O请求的用户进程会被置于阻塞状态,等待I/O完成。
  • 中断使用:每当一个数据单元(如字节/字)传输完成,设备控制器就会向CPU发送一个中断请求。CPU响应中断,暂停当前进程,转而执行驱动程序的中断服务程序(ISR)。ISR负责处理刚完成的数据,并启动下一次数据传输,然后返回到被打断的进程。这个过程会频繁发生,直到整个数据块传输完毕。

  • 直接内存存取 (DMA) 方式

若采用DMA方式,驱动程序将数据传输任务完全委托给DMA控制器,进一步解放CPU。

  • 处理过程:驱动程序首先对DMA控制器进行初始化(设置源地址、目标地址、数据块大小等),然后向设备发出“启动DMA传送”的命令。完成这些设置后,驱动程序便放弃CPU,由调度程序切换到其他进程。
  • CPU与外设关系:CPU仅在I/O操作的开始(进行初始化)和结束(响应中断)时介入。在整个数据块的传输过程中,CPU可以并行执行其他进程,数据传输由DMA控制器和设备控制器协同完成。
  • 进程状态:发起I/O请求的用户进程同样会被置于阻塞状态。
  • 中断使用:与中断驱动方式不同,DMA方式下,中断只在整个数据块传输完成时才由DMA控制器产生一次。CPU响应这个“DMA完成”中断,执行中断服务程序,该程序负责进行收尾工作(如检查错误)并唤醒(解除阻塞)等待的用户进程。

【2013-25】用户程序发出磁盘 I/O 请求后,系统的处理流程是:用户程序→系统调用处理程序→设备驱动程序→中断处理程序。其中,计算数据所在磁盘的柱面号、磁头号、扇区号的程序是( )。

A. 用户程序

B. 系统调用处理程序

C. 设备驱动程序

D. 中断处理程序

解析

答案:C

设备驱动程序的核心职责是充当“翻译官”,将上层软件发出的抽象I/O请求(如“读取逻辑块号X”)转换为具体硬件能识别的物理指令。计算磁盘的柱面号、磁头号、扇区号(CHS地址)正是这种从逻辑到物理地址转换的典型过程。用户程序和系统调用处理的是逻辑地址,中断处理程序则是在I/O完成后进行响应。

【2022-32】下列关于驱动程序的叙述中,不正确的是( )。

A. 驱动程序与I/O控制方式无关

B. 初始化设备是由驱动程序控制完成的

C. 进程在执行驱动程序时可能进入阻塞态

D. 读/写设备的操作是由驱动程序控制完成的

解析

答案:A.

该叙述是错误的。设备驱动程序的内部实现逻辑与I/O控制方式紧密相关。例如,采用程序I/O方式的驱动程序需要循环查询,而采用中断或DMA方式的驱动程序则涉及启动设备后阻塞进程、并由中断唤醒的逻辑。因此,I/O控制方式直接决定了驱动程序的编码方式和行为。其他选项(B, C, D)均是驱动程序的正确描述。

在一个采用中断驱动I/O模型的多任务操作系统中,当一个用户进程的写磁盘请求被传递给设备驱动程序,并且驱动程序成功启动了磁盘控制器后,该用户进程通常会( )。

A. 保持运行状态,并通过循环查询等待I/O操作完成

B. 被操作系统转换为内核线程,专门负责监督此次I/O

C. 进入阻塞状态,直到I/O操作完成产生中断后才被唤醒

D. 立即从系统调用返回,并在用户态继续执行后续代码

解析

正确答案:C

  • 为了实现CPU与I/O设备的并行工作,提高系统效率,现代操作系统在处理耗时的I/O操作时,不会让CPU“忙等”。驱动程序启动硬件后,会请求操作系统将当前进程阻塞,并将其从运行队列中移出。然后,CPU调度程序会选择另一个处于就绪状态的进程来运行。当硬件I/O操作完成后,会通过中断信号通知CPU,操作系统在中断处理程序中再将原先被阻塞的进程唤醒(置为就绪态),等待下一次调度。
  • A描述的是程序I/O方式。
  • B和D描述的是其他更复杂的模型(如内核线程或非阻塞 I/O),但最基本和典型的处理方式是阻塞进程。

下列任务中,属于一个具体的块设备驱动程序(例如,某款SSD的驱动)职责范围的有( )。

Ⅰ. 接收来自文件系统的以逻辑块号为单位的读写请求

Ⅱ. 管理磁盘上的空闲块列表和文件目录结构

Ⅲ. 将逻辑块号地址转换为设备内部的物理地址(如页、块地址)

Ⅳ. 向中断控制器注册一个中断服务程序,以处理I/O完成事件

A. Ⅰ、Ⅱ

B. Ⅱ、Ⅲ

C. Ⅰ、Ⅲ

D. Ⅰ、Ⅲ、Ⅳ

解析

正确答案:D

  • Ⅰ (属于驱动程序):正确。设备驱动程序的“上层接口”就是用来接收来自更高层软件(通常是文件系统或块设备层)的标准化I/O请求,这些请求以逻辑块号(LBN)的形式给出。
  • Ⅱ (不属于驱动程序):错误。管理文件如何在磁盘上存储(目录结构)、哪些块被占用或空闲,这是文件系统的核心职责。设备驱动程序只关心对“块”的读写,不理解“文件”或“目录”的概念。
  • Ⅲ (属于驱动程序):正确。这是设备驱动程序最核心的“翻译”工作之一。它负责将上层传来的抽象逻辑地址,转换为具体硬件设备能够理解的物理地址或内部地址。
  • Ⅳ (属于驱动程序):正确。在现代中断驱动或DMA的I/O模型中,I/O操作是异步完成的。当硬件完成任务后,会通过一个硬件中断来通知CPU。设备驱动程序必须在初始化时,就向系统的中断管理模块注册自己的中断服务程序,这样当中断发生时,操作系统才知道应该调用哪段代码来处理后续事宜(如唤醒等待的进程、检查错误等)。

中断处理程序

整个中断过程包括两个阶段:中断响应和中断处理。中断响应完全由硬件完成,而中断处理则由CPU执行一个中断服务程序完成。虽然不同的中断源对应的中断服务程序不同,但是所有中断服务程序的结构是相同的,包括三个阶段:准备阶段、处理阶段和恢复阶段.具体过程见章节《中断与异常》

  1. 在 I/O 时,设备控制器如果已经准备好数据,则会通过中断控制器向 CPU 发送中断请求;
  2. 保护被中断进程的 CPU 上下文;
  3. 转入相应的设备中断处理函数;
  4. 进行中断处理;
  5. 恢复被中断进程的上下文;

【例题】:以下关于I/O子系统的描述中,错误的是( )   题目来源:袁习题P252

A. I/O子系统包含I/O软件和I/O硬件两大部分

B. I/O软件包含用户空间I/O软件部分和内核空间I/O软件部分

C. 内核空间I/O软件包含设备无关软件、设备驱动程序和中断服务程序

D. 直接控制I/O硬件的是设备驱动程序,而不是中断服务程序

解析

【解析】选 D; 直接控制I/O硬件的是设备驱动程序,而不是中断服务程序,这个说法是不准确的。设备驱动程序和中断服务程序共同协作来直接控制I/O硬件。

  • 设备驱动程序负责发起操作。它通过向I/O控制器的命令寄存器、数据寄存器、地址寄存器等写入值,来启动一个I/O任务。
  • 中断服务程序负责响应操作的完成。当硬件完成任务后,它会触发一个中断。中断服务程序会运行,它需要直接与硬件交互,例如从状态寄存器中读取操作结果,向硬件发送确认信号以清除中断等。
  • 因此,不能说中断服务程序不直接控制硬件。它们是在I/O操作的不同阶段分别对硬件进行直接控制。该选项的“而不是”使得这个论述变得错误。

这里用一个实例来将发出一个I/O请求后发生的事串起来(该段来自袁春风《计算机系统基础》)

int 1en, n, buf[ BUFSIZ];
FILE *fp;
...
fp= fopen("bin_file.txt","r");  
n= fread(buf,sizeof(int),BUFSIZ,fp);

Info

例题:在IA-32+Linux系统中,假设某用户程序P中有以上一段C代码:

假设文件bin_file.txt已经存在磁盘上且存有足够多的数据,以前未被读取过。回答下列问题或完成下列任务。

①执行第4行语句时,从用户程序的执行到调出内核中的I/0软件执行的过程是怎样的?要求画出函数之间的调用关系,并用自然语言描述执行过程。

②执行第5行语句时,从用户程序的执行到调出内核中的I/0软件执行的过程是怎样的?要求画出函数之间的调用关系。

③执行第5行语句时,通过陷阱指令陷入内核后,底层的内核IO软件的大致处理过程是怎样的?

解:①如图8.23所示,当执行到用户程序P中第4行语句时,将转入C标准库函数fopen()执行,根据fopen()函数源代码可知,fopen()将调用系统调用函数open(),而open() 系统调用对应的指令序列中有一条陷阱指令int0x80(或sysenter),当执行到该陷阱指令时,将从用户态陷入内核态执行,在内核态首先执行的是system_call程序,该程序中再根据系统调用号转到对应的open系统调用服务例程sys_open执行,文件打开的具体工作由sys_open完成。因为将要打开的文件已经存在,因此该函数可以成功执行

1760350159507-d89d32e2-0004-45d0-b0ff-d3abffdb2f30.png

②

1760350159242-12530d59-5161-410b-9e99-e3e2a455a5f6.png

③因为用户进程使用fread()函数读取的是一个普通的磁盘文件,所以应采用DMA控制I/O方式进行磁盘读操作。通过系统调用陷入内核后,底层的内核I/O软件的大致处理过程如下:

  • 首先,由内核空间中与设备无关的I/O软件完成以下相关操作:根据文件bin_file的文件描述符fd(执行fopen()函数后得到一个指向结构FILE的指针fp,在fp所指结构中包含了打开文件的文件描述符fd),找到对应的文件描述信息,根据相应的文件描述信息可确定相应的磁盘设备驱动程序;根据文件当前指针确定所读数据在抽象的块设备中的逻辑块号;检查用户所需数据是否在高速缓存RAM中,以判断是否需要读磁盘。因为文件bin_file未曾被读取过,所以肯定不会在高速缓存RAM中,同时也不会在用户缓冲区,因而需要调用相应的磁盘驱动程序执行读磁盘操作。
  • 然后,在磁盘驱动程序中,将会完成以下操作:检查磁盘驱动器的电机是否运转正常,将逻辑块号转换为磁盘物理地址(柱面号、磁头号、扇区号),对将要接收磁盘数据的主存空间进行初始化,对DMA控制器中的各个I/O端口进行初始化;然后,发送“启动DMA传送”命令以启动具体的I/O操作;最后调用处理器调度程序以挂起当前用户进程P,并使CPU转而执行其他用户进程。
  • 最终,当DMA控制器完成I/O操作后,向CPU发送一个“DMA完成”中断请求信号,CPU调出相应的中断服务程序执行。CPU在中断服务程序中,解除用户进程P的阻塞状态而使其进入就绪队列,然后中断返回,再回到被打断的进程继续执行。下次处理器调度时用户进程P有可能会被调度到处理器上继续执行。

I/O硬件与软件的接口

I/O设备一般是由执行I/O操作的机械部分和执行控制I/O的电子部件组成。通常将这两部分分开,执行I/O操作的机械部分就是一般的I/O设备,而执行控制I/O的电子部件则称为I/O接口或设备控制器或I/O适配器(\(adapter\))。

I/O设备

画板

Info

【补充】

  • 字符设备 :以字节/字符为单位进行数据交换,不可寻址。你不能指定去读写第几个字节,只能像水流一样顺序访问。鼠标、键盘,打印机、 都是典型的字符设备。
  • 块设备 (Block Device):以固定大小的数据块(Block)为单位交换,可以寻址。可以发出指令“读取第N个数据块”,支持随机访问。 磁盘、固态硬盘、U盘、光盘都是块设备。

I/O接口(设备控制器)

外部设备种类繁多,且具有不同的工作特性,因而它们在工作方式、数据格式和工作速度等方面存在很大差异。此外,由于CPU、内存等计算机主机部件采用高速元器件,使得它们和外设之间在技术特性上有很大的差异,它们各有自己的时钟和独立的时序控制,两者之间采用完全的异步工作方式。为此,在各个外设和主机之间必须要有相应的逻辑部件来解决它们之间的同步与协调、工作速度的匹配和数据格式的转换等问题,该逻辑部件就是外设的I/O接口或称I/O模块。各种I/O控制器或设备控制器(包括适配器或适配卡)都是I/O接口,而在有些大型机中的I/O模块就是担负大量复杂的外设控制任务的通道或I/O处理器。

下图给出了常见的几种连接外设的插座,I/O接口在主机一侧与I/O总线相连,在外设一侧提供相应的连接器插座,在插座上连上相应的连接外设的电缆,就可以将外设通过设备控制器连接到主机。

1760350159817-965ca935-adc8-467b-aaef-2f5230d5bf93.png1760350160053-2bda3617-908f-4443-82e2-7b09d292d19d.png

设备控制器的主要功能是,控制一个或多个I/O设备,以实现I/O设备和计算机之间的数据交换。它是CPU与I/O设备之间的接口,接收从CPU发来的命令,去控制I/O设备工作,使处理机能够从繁杂的设备控制事务中解脱出来。设备控制器是一个可编址的设备,当它仅控制一个设备时,它只有一个唯一的设备地址;若控制器可连接多个设备,则应含有多个设备地址,每一个设备地址对应一个设备。可把设备控制器分成两类:一类是用于控制字符设备的控制器,另一类是用于控制块设备的控制器。

I/O接口(设备控制器)的组成(基本结构)

外部设备通过I/O接口连接总线,早期设备均通过接口直接连接在系统总线上与CPU、主存相连,现代计算机普遍采用分离的层次总线结构,将不同速度的设备连接在不同层次的I/O总线上,I/O总线再通过扩展总线控制器、桥芯片或者通道处理器与CPU进行数据交互。

早期单总线结构

现代多总线结构

I/O接口内部主要包括总线接口和内部接口两部分,如下图所示。连接总线的总线接口必须按总线标准进行设计,这部分逻辑为接口的标准部分。而连接设备的内部接口逻辑因设备而异,是非标准的。虽然不同类型的I/O接口的内部电路、控制方式、复杂性差异较大,但一般I/O接口都应包括如下基本的功能部件。

  1. 数据缓冲寄存器(DBR):用于缓冲数据,以匹配CPU与外部设备之间的速度差异。CPU执行输入操作时,DBR存放从I/O设备读取的数据,该数据将被CPU通过总线读取并送入CPU寄存器中;执行输出操作时DBR暂存CPU送来的数据,该数据最终会被输出至具体外部设备。
  2. 设备 状态寄存器:用于反馈设备状态,常见的状态信息如设备忙、设备就绪、设备错误等。在程序查询方式中,CPU通过读取状态寄存器来判断设备的状态,以确定程序下一步进行什么操作。
  3. 设备命令寄存器(也叫 控制寄存器 ):用于接收CPU发送的设备控制命令,如设备复位、设备识别、读写控制等,不同设备所能支持的命令不同,简单设备甚至没有命令寄存器,如简单的键盘输入和字符终端输出设备。

Info

状态寄存器和控制寄存器在传送方向上是相反的,而且CPU对它们的访问在时间上一般是错开的,因此有的I/O接口将它们合二为一;

  1. 设备存储器:这部分并不是必需的,常用于设备自身的运算和处理,如显卡中的显存。(之前介绍设备驱动程序统一接口里面例子的惠普打印机里的页面数据缓冲区也是一个存储器 ram)
  2. 地址译码器和 I/O 控制逻辑:I/O控制逻辑除了要接收地址线和控制线发来的来自处理机的信息,还要能对控制寄存器中的命令字进行译码,并将译码得到的控制信号通过设备控制器与外设的接口送到外设(实现设备控制),同时将数据缓冲寄存器的数据发送到外设或从外设接收数据到数据寄存器。另外,它还要具有收集外设状态到状态寄存器的功能。

1760362199835-54de7b42-9f0a-4197-91c6-37a24647be78.png

需要注意,图中与 IO 接口相连的三类总线(数据线、地址线与控制线)都是双向的,下面介绍一下这些总线分别传送什么信息。

  1. 数据总线 :双向的,主要用于在CPU、I/O接口和主存之间传输实际的数据和信息。其传输的内容包括:

  2. 真正的I/O数据:在CPU与外部设备之间进行读写操作时,实际的数据通过数据缓冲寄存器(DBR)并在数据总线上传输。

  3. 设备控制命令:CPU发送给设备的控制命令(也称为控制字/命令字)会先写入I/O接口的命令(控制)寄存器,这个写入过程是通过数据总线完成的。
  4. 设备状态信息:I/O接口的状态寄存器中的状态信息(有时也叫状态字),也是通过数据总线被CPU读取的。

  5. 地址总线 :地址总线主要用于指定要进行读写操作的位置。它也是双向的,因为不仅CPU可以指定地址,其他主设备(如DMA模式下的I/O接口)也可以。其传输的信息包括:

  6. I/O端口或设备寄存器的地址:当CPU需要与I/O接口内的特定寄存器(如数据缓冲寄存器、命令/状态寄存器)交互时,会将这些寄存器唯一的地址加载到地址总线上。I/O 接口内的地址译码器会识别这个地址以选中相应的寄存器。

  7. 主存地址:当I/O接口成为主设备并发起DMA请求时,它会自己将要读或写的主存地址发送到地址总线上,以实现设备和内存之间直接的数据交互。

  1. 控制总线 :控制总线是双向的,它不传输数据本身,而是传输用于协调和管理总线操作的命令、时序和状态信号。其传输的信息包括:

  2. 总线控制命令和时序信号:例如读/写信号、时钟信号等,用于指示总线上的操作类型和同步各部件。

  3. 总线控制权协商信号:(现代总线普遍支持总线主控技术,I/O接口也可成为主设备)当I/O接口需要作为主设备发起DMA请求时,它会通过控制总线发送总线请求信号以获得总线控制权。
  4. 应答信号:用于确认操作是否完成或响应请求。
  5. 中断响应信号:用于处理来自设备的中断请求。
通过数据线写入控制寄存器的控制命令和通过控制总线发送的控制信息有什么区别
  1. 控制命令 (通过数据线写入控制寄存器)

这是 “What” - 具体做什么事

  • 性质: 这是一个数据值。它是一个具体的二进制代码(例如之前介绍设备驱动程序统一接口的例子,B1H 代表“初始化打印机”,B3H 代表“执行打印”)。
  • 目的: 它告诉设备控制器要执行一个具体的、特定的任务。这个命令是设备相关的,不同设备的命令字完全不同。
  • 工作方式: CPU 像写入普通数据一样,将这个命令字(如 B1H)放到数据总线上,同时在地址总线上指定控制寄存器的地址,然后在控制总线上发出一个通用的“写入”信号。
  1. 控制信息 (通过控制总线发送)

这是 “How” 和 “When” - 如何协调通信过程

  • 性质: 这是一个信号,通常是电平的高低。它不是一个复杂的数据值,而是一个用于同步和管理总线操作的状态指示。
  • 目的: 它负责协调整个数据传输的过程。它不关心传输的数据是什么,只关心传输本身如何进行。例如:
    • 现在是“写入”操作还是“读取”操作?
    • 总线现在归谁使用?(总线请求/授权)
    • 数据准备好了吗?(应答信号)
    • 设备有紧急情况需要CPU处理吗?(中断请求)
  • 工作方式: 控制总线是多条独立的信号线集合,每条线都有特定的功能(如 I/O Write线, Interrupt Request线)。

简单来说:CPU 使用控制总线来“建立通信并说明要做的是写操作”,然后把“要写入的具体内容是什么(即那个 B3H 命令)”放在数据总线上。

通过上述 IO 接口中的基本组成的介绍,我们可以看出 IO 接口具有以下作用:设备寻址、数据交互、设备控制、状态检测、数据缓冲、格式转换、数据检错、纠错等。

需要注意一件事,下面这道真题里面的中断类型号也会在 I/O 总线的数据线上进行传输,但是它并不来源于上图中的这种设备控制器,它是可编程中断控制器根据中断请求响应判优后生成的,具体解释见下面的例题解析

【2012-21】下列选项中,在I/O总线的数据线上传输的信息包括( )。

Ⅰ. I/O接口中的命令字

Ⅱ. I/O接口中的状态字

Ⅲ. 中断类型号

A. 仅Ⅰ、Ⅱ

B. 仅Ⅰ、Ⅲ

C. 仅Ⅱ、Ⅲ

D. Ⅰ、Ⅱ、Ⅲ

【例题】下列关于中断控制器的说法,错误的是()

A. 中断控制器负责记录各种中断请求信号,中断判优以及中断屏蔽

B. 中断控制器与外部设备的 I/O 控制器直接相连

C. 中断控制器在 CPU 响应中断控制器的过程中会将中断向量送到数据线上

D.中断控制器属于 IO 控制器

解析

答案 : C

下面图片中的就是中断控制器

题图题图

从图中可以看出,来自各个外设的中断请求记录在中断请求寄存器中的对应位,每个中断源有各自对应的中断屏蔽字,在进行相应的中断处理之前它被送到中断屏蔽字寄存器中。在CPU执行程序代码时,每当完成当前指令的执行、取出下一条指令之前,都会通过采样中断请求信号引脚(如图中的INTR)来自动查看有无中断请求信号。若有,则会发出一个相应的中断回答信号,启动图中的“中断查询”线,在该信号线的作用下,所有未被屏蔽的中断请求信号一起送到一个中断判优电路中,判优电路根据中断响应优先级选择一个优先级最高的中断源,然后用一个编码器对该中断源进行编码,得到对应的中断源设备类型号(即中断源的标识信息,称为中断类型号)。CPU取得中断源的标识信息后,经过一系列相应的转换,就可得到对应的中断服务程序的首地址(中断向量),在下一个指令周期开始,CPU执行相应的中断服务程序。

因此 A 显然是正确的;B 的话,每个外部设备(如键盘、磁盘)都有自己的I/O控制器。当设备需要中断时,是它的I/O控制器发出中断请求信号(IRQ),这条IRQ信号线会直接连接到中断控制器的一个输入引脚上(如图中的IR0-IR7),所以这个叙述是正确的。C 错误,送到数据线的是中断类型号,CPU 根据该类型号查询中断向量表才能得到中断向量(即对应的中断服务程序的入口地址)。

D 正确,这其实是 21 年真题的一个选项,下面是具体解释;I/O控制器(或称I/O接口) 的广义定义是CPU与外部世界(包括外设)进行通信的桥梁,CPU必须能够通过编程来控制和查询这些桥梁。中断控制器本身是一个复杂的、可编程的芯片,它内部有多个寄存器(中断请求寄存器、中断屏蔽寄存器、服务中寄存器等)。CPU为了初始化中断系统、设置中断屏蔽或读取中断状态,必须通过标准的I/O操作(如IN/OUT指令或内存映射I/O的Load/Store指令)来读写这些寄存器。既然CPU通过I/O操作来控制它,那么中断控制器本身就符合I/O控制器的定义。它是一个非常特殊的、用于管理其他I/O设备中断请求的I/O控制器。

Note

I/O指令: 在底层I/O软件中,可以将控制命令送到控制寄存器来启动外设工作;可以读取状态寄存器来了解外设和设备控制器的状态;可以通过直接访问数据缓冲寄存器来进行数据的输入和输出。

当然,这些对数据缓冲寄存器、控制/状态寄存器的访问操作是通过相应的指令来完成的,通常把这类指令称为I/O指令。因为重点这些I/O指令只能在操作系统内核的底层I/O软件中使用,因而它们是一种特权指令。例如,在IA-32中,提供了4条专门的I/O指令:\(in、ins、out\) 和\(outs\)。其中\(in\)和\(ins\)指令用于将设备控制器中某个寄存器的内容取到CPU内的通用寄存器中;out\(和\)outs用于将通用寄存器的内容输出到设备控制器的某个寄存器中。

I/O接口的类型

画板

I/O端口及其编址

通常把设备控制器中的数据缓冲寄存器、状态/控制寄存器等统称为\(I/O\)端口(\(I/O\ port\))。数据缓冲寄存器简称为数据端口,状态/控制寄存器简称为状态/控制端口。为了便于CPU对外设的快速选择和对I/O端口的寻址,必须对I/O端口进行编址,所有I/O端口编号组成的空间称为I/O地址空间。I/O端口的编址方式有两种:统一编址方式和独立编址方式。

统一编址(内存映射编址) 独立编址(I/O映射方式)
概念 把I/O端口(寄存器)当成主存的单元进行编址 I/O端口地址与存储器地址无关
特点 不需要专门的I/O指令,用统一的 LOAD/STORE 访存指令就可以实现I/O端口与CPU寄存器的数据传输,程序设计灵活性高; 独立编址CPU需要设置专门的输入输出指令访问端口(如 X86 机器中,用 MOV 指令访存,用 IN/OUT 指令访问外部设备)
优点 + 端口有较大的编址空间;
+ 读写控制逻辑电路简单;
+ 由于I/O访问与主存访问共用一组指令,因此它的保护机制可由分段或分页存储管理来实现,而无需专门的保护机制;
+ 使用专用I/O指令,程序编制清晰即方便编程;
+ I/O端口地址位数少,地址译码速度快;
+ I/O端口的地址不占用主存地址空间
缺点 + 端口占用了主存地址空间,使主存地址空间变小;
+ 外设寻址时间长(地址位数多,地址译码速度慢)
+ I/O指令类型少,一般只能对端口进行传送操作,程序设计灵活性差;
+ 需要CPU提供存储器读/写、I/O设备读/写两组控制信号,增加了控制逻辑电路的复杂性
I/O与存储器的区分 通过不同地址码区分(根据地址范围区分) 通过不同指令区分,I/O指令的地址码部分给出I/O端口号( 由于主存和 I/O 独立编址,因此二者的部分地址空间会重叠,因此不同的指令会生成不同的总线控制信号来表示地址总线上的地址是主存还是 I/O 地址 )
采用该方式的处理器 MIPS、ARM 等 RISC 处理器 Inter x86 处理器
地址分布图 1760371393920-39db8978-9af5-44ef-920e-20fca1191bdd.png 1760372725878-2c911cde-af01-4f93-a4de-78d383cf049c.png
注意事项 + 通过扩展卡扩展的设备以及热插拔设备的 IO 地址是在计算机启动过程中动态分配的;
+ I/O 地址虽然映射到了主存空间,但是由于接口中的数据是动态变化的,因此不能用 cache 进行缓存,否则 CPU 无法了解设备的实时状态变化。
同样热插拔设备的端口地址是在启动过程中动态分配的

I/O控制方式

对设备的控制,早期是使用轮询的可编程方式,后来发展为使用中断的可编程I/O方式。随着DMA控制器的出现,从以字节为单位,改为以数据块为单位进行转输,大大地改善了块设备的I/O性能。I/O通道的出现,又使对I/O操作的组织和数据的传送都能独立进行,而无需CPU的干预。应当指出,在I/O控制方式的整个发展过程中,始终贯穿着这样一条宗旨,即尽量减少主机对I/O控制的干预,把主机从繁杂的I/O控制事务中解脱出来,以便更多地去完成数据处理任务。

程序查询(程序直接控制)方式

计组考纲这里是程序查询方式,操作系统这部分是 IO 控制方式--轮询方式

程序控制方式是指输入输出完全依靠CPU执行程序实现,当CPU要与设备进行数据交换时,首先设置接口命令寄存器启动设备;设备准备的过程中,CPU通过读取接口中的状态寄存器查询设备是否已就绪,根据查询结果决定下一步操作究竟是进行数据传送还是等待。这种控制方式的接口设计简单,但是CPU与外部设备只能串行工作,CPU会浪费大量的时间进行查询和等待,系统效率较低。程序控制方式多见于早期单任务操作系统中,现代计算机在操作系统启动引导至多任务操作系统之前也采用这种方法与设备交互。

简单设备查询流程

以简单键盘输入设备为例,该设备没有命令寄存器,按键按下时键盘控制器会将键盘的键值 ASCII 数据存放在在键盘数据缓冲寄存器 DBR 中,并同时将状态寄存器 DSR 中对应的 “数据就绪 Ready” 位置为 “1”,表示当前有按键数据。当 CPU 需要从键盘获取按键数据时,首先通过总线读取 DSR 寄存器,然后查询并判断 DSR 中的 Ready 位的状态,如果为 “0”,则继续查询直至该位为 “1”;如果为 “1”,则通过总线读取 DBR 中的按键编码,完成操作后 DSR 中的 Ready 位会自动归 “0”。具体访问流程如图所示,如果需要获取多个按键,只需将这个流程加上循环控制即可。

1760440059494-0e2dcd45-f205-40b5-9235-d90e34be7ddd.png

          lui  t0, 0xffff0000         # 载入键盘 DSR 内存映射地址至 t0
keyPoll:  lbu  t2, (t0)              # 载入键盘 DSR 的值至 t2
          andi t2, t2, 1             # 获取最低位 Ready 位
          beq  t2, 0, keyPoll        # 如果 Ready==0 则继续查询
          lui  t0, 0xffff0004         # 载入键盘 DBR 内存映射地址至 t0
          lbu  s0, (t0)              # 读取键盘 DBR 中的字符数据至 s0
          MOV  DX, 0x0000             # 载入键盘 DSR 端口地址至 DX
keyPoll:  IN   AL, DX                 # 载入键盘 DSR 的值至 AL
          TEST AL, 1                  # 测试就绪位 Ready
          JZ   keyPoll                # 如果 Ready==0 则继续查询
          MOV  DX, 0x0004             # 载入键盘 DBR 端口地址至 DX
          IN   AL, DX                 # 读取键盘 DBR 中的字符数据到 AL
复杂设备程序查询流程

CPU 与复杂设备进行数据交互时,首先要查询设备的状态,只有设备就绪后,才可以通过总线向 I/O 接口发送命令与参数来启动设备,以明确告知设备要具体执行什么操作;设备收到命令后即刻去准备或处理,这个过程可能需要较长的时间,也就是常说的设备准备阶段。设备准备好后会将状态寄存器中相关位置位,表示命令执行完毕或准备就绪。而 CPU 在启动设备后就开始不断查询设备状态,当设备就绪时即可进行实际的数据传输,具体处理流程如图所示。

1760442629496-ab6b2f1d-28d8-41ad-a9ea-29e8db4c3f39.png

独占查询与定时查询

程序查询方式中CPU要不断查询I/O接口中的状态寄存器DSR,当设备就绪时才能进行下一操作,否则继续查询。通常将这种反复查询的过程称为轮询,对于字符设备,一次轮询只能传输一个字节或字,而块设备一次轮询可以传输一个数据块。

轮询主要有两种策略,分别是忙等待和定时轮询。

1760443006140-12d94266-ae5f-44d7-a5f1-3f26cd2ed773.png

忙等待策略也称为独占式查询,具体如图所示。假设CPU执行某用户程序需要访问I/O设备,那么用户程序中需要启动I/O设备,这里启动设备是通过对I/O 端口发送命令参数实现的,设备一旦收到cpu发送过来的启动命令,就开始漫长的数据准备过程,当然这里的漫长是相对CPU的速度而言的,从启动设备到设备就绪这一段漫长的时间里面,CPU只能反复读取设备的状态寄存器,判断设备是否就绪,如果没有就绪则继续读取状态字,这种方式称为轮询等待,busy-waiting,也就是在这段时间内CPU执行的是一个查询状态的循环,这个循环退出的逻辑就是设备状态字表明设备就绪,一旦设备就绪,用户程序就可以通过相应的I/O指令读取特定端口中的数据,完成实际的数据传输,注意这里一次轮询只能完成一个数据单元的传输,这种独占式查询,CPU浪费了大量的时间进行查询,并且这个阶段CPU不能执行其他任务。

通常在单任务操作系统中可采用这种方式,此时CPU也不需要执行其他任务;另外对于超高速设备,由于设备响应快,这种方式也是可以接受的。

定时查询方式应用到了定时中断技术,当cpu启动设备时,同时启动一个定时器,设备准备数据的过程中,CPU不再轮询等待,而是进行进程调度,将当前进程加入I/O等待队列,并调度新的用户进程P2运行。定时器时间到时,会产生一个定时中断,定时中断会触发CPU中断用户进程2或者其他进程,转去执行定时中断服务程序,中断服务程序的任务就是查询设备状态,如果设备没有准备好,继续启动新的定时中断,如果设备准备好,应该唤醒进程P1,中断服务完毕,继续执行用户进程P2,随着时间片的轮转,用户进程P1会被进程调度程序重新调度运行,该程序会完成实际数据传输。

显然这里定时器如何设置可能是一个问题,定时过短,可能数据还没有准备好,定时过长数据可能已经早就ok了而没有得到及时处理。定时轮询方式中CPU可以执行其他任务,有效节约了CPU时间,适用于外部设备不支持中断的多任务操作系统。

然而真题里面考察的定时查询和这个模型并不一样,真题里的定时查询其实就是把独占查询中查询的比例从 100%下降了,并没有发起调度让其他进程执行;

【2011-22】某计算机处理器主频为50MHz,采用定时查询方式控制设备A的I/O,查询程序运行一次所用的时钟周期数至少为500。在设备A工作期间,为数据不丢失,每秒需对其查询至少200次,则CPU用于设备A的I/O的时间占整个CPU时间的百分比至少是( )。

A. 0.02%

B. 0.05%

C. 0.20%

D. 0.50%

解析

正确答案是 C

因为每秒需对其查询至少200次且查询程序运行一次所用的时钟周期数至少为500,所以每秒查询至少需要200×500=100000=0.1M个周期,又因为CPU主频为50MHz,所以CPU用于设备A的I/O的时间占整个CPU时间的百分比至少为0.1M/50M=0.20%。

【2018-43】假定计算机的主频为500MHz,CPI为4。现有设备A和B,其数据传输率分别为2MBps和40MBps,对应I/O接口中各有一个32位数据缓冲寄存器。请回答下列问题,要求给出计算过程。

(1) 若设备A采用定时查询I/O方式,每次输入/输出都至少执行10条指令。设备A最多间隔多长时间查询一次才能不丢失数据?CPU用于设备A输入/输出的时间占CPU总时间的百分比至少是多少?

解析

第一问。程序定时向缓存端口查询数据,由于缓存端口大小有限,必须在传输完端口大小的数据时访问端口,以防止部分数据没有被及时读取而丢失。设备A的数据传输率为2MBps,设备A准备32位数据所用时间为32bit/2MBps=4B/2MBps=2μs,所以最多每隔2μs必须查询一次。

第二问。

  • 方法一:通过时间计算

因为计算机的主频为500MHz,时钟周期为2ns,CPI为4,平均执行一条指令需要2ns×4=8ns,每次输入/输出都至少执行10条指令,所以每次输入/输出需要CPU时间为8ns×10=80ns,又因为根据第一问,设备A最多每隔2μs必须查询一次,所以CPU用于设备A输入输出的时间占CPU总时间的百分比至少是80ns/2μs=4%。

  • 方法二:通过频率计算

因为计算机CPI为4,每次输入/输出都至少执行10条指令,所以每次输入/输出都至少需要4×10=40个时钟周期,又因为根据第一问,设备A最多每隔2μs必须查询一次,即每秒的查询次数至少是1s/2μs=0.5M,所以CPU每秒用于设备A输入/输出的时钟周期数至少为40×0.5M=20M,又因为计算机的主频为500MHz,即每秒有500M个时钟周期,所以CPU用于设备A输入输出的时间占CPU总时间的百分比至少是20M/500M=4%。

因此这题等价于求为了服务这个设备,CPU的最小时间代价,占设备所要求的时间周期的比例是多少?

袁书例题:假定查询程序中所有操作(包括读取并分析状态、传送数据以及重启用户程序等所有步骤)所用的时钟周期数至少是 400 个,处理器的主频为 500MHz,即处理器每秒钟产生 500×10⁶ 个时钟周期。假定设备一直持续工作,采用定时查询方式,则以下 3 种情况下,CPU 用于 I/O 的时间占整个 CPU 时间的百分比各是多少?

  1. 鼠标必须每秒钟至少被查询 30 次,才能保证不错过用户的任何一次移动。
  2. 软盘以 16 位为单位进行数据传送,数据传输率为 50kBps,要求没有任何数据传送被错过。
  3. 硬盘以 16 字节为单位进行数据传送,数据传输率为 4MBps,要求没有任何数据传送被错过。
解析

解:对于查询方式,CPU 用于输入输出的时间由查询次数乘以查询操作时间得到。

  1. 对于鼠标,每秒钟内用于查询的时钟周期数至少为 30×400 = 12 000,因此,花费的处理器时钟周期的百分比至少为 12000/(500×10⁶)≈0.002%。显然,CPU 对鼠标的查询操作对性能的影响不是很大。
  2. 对于软盘,因为每次数据传送的单位为 16 位,占两个字节,所以只有当查询的速率达到每秒 50kB/2B = 25k 次时才能保证没有任何数据传送被丢失。因此,每秒钟内用于查询的时钟周期数为 25k×400,在整个 CPU 时间中所占的百分比为 25k×400/(500×10⁶) = 2%。这个开销非常大,但在只有少量像软盘这样的 I/O 设备的低端系统中,这个开销是可以忍受的。
  3. 对于硬盘,要求每次以 16 字节为单位进行查询,所以查询的速率应达到每秒 4MB/16B = 250k 次的速度,故每秒钟内用于查询的时钟周期数为 250k×400,用于硬盘输入输出的时间占整个 CPU 时间的百分比为 250k×400/(500×10⁶) = 20%。也就是说,CPU 的五分之一时间被用于查询硬盘,显然,对硬盘用查询方式是不可取的。 如果软盘和硬盘仅有 25%的时间是活动的,那么,操作系统只要在设备被激活时进行查询,所以查询的平均开销将被分别降到 0.5%和 5%。

尽管这样降低了开销,但是一旦操作系统发出一个对设备的启动命令,它就必须接连不断地查询,因为操作系统不知道什么时候设备会响应并准备好一次传送。这种一旦设备被启动,CPU 就一直持续对设备进行查询的方式,称为独占查询方式。

程序中断I/O方式

程序查询方式CPU占用率比较高,定时查询方式中如何设置定时器长度也是比较麻烦的一件事情,只适合IO设备不支持中断的模式,而中断方式进一步提升了CPU的效率。我们来看看中断控制方式的过程。

1760457073128-ecaa0d3f-af32-4271-af2a-384636ddf5e8.png

  1. 用户系统调用:用户进程P1通过系统调用read()函数从设备读取数据,该系统调用会使操作系统进入内核态。
  2. 驱动启动设备:由设备驱动程序负责将读命令以及相关参数通过I/O接口发送给I/O设备,也就是启动设备的过程。
  3. 操作系统进程调度:操作系统将用户进程P1放入I/O等待队列,并通过进程调度进行上下文切换,调度用户进程P2运行,P2的执行和设备准备阶段是并行的。
  4. 设备中断请求:当设备准备好数据后,立刻主动向CPU发出中断请求,告知CPU数据准备就绪,主动中断请求是中断控制方式的核心,可以避免不必要的轮询。
  5. CPU中断服务:CPU暂停当前进程的执行,转去执行设备中断服务程序。中断服务程序的主要任务是完成实际的数据传输,唤醒I/O等待队列中的P1进程
  6. CPU恢复运行:中断服务程序的最后一条指令是中断返回指令,该指令执行完毕后就会返回断点继续执行;而用户进程P1由于已经被设置为就绪状态,因此总会获得CPU时间片轮转运行,从而完成后续I/O操作,操作系统最终返回用户态。

相比独占式程序查询方式,中断控制方式不需要轮询设备状态。另外,设备主动请求中断的方式比定时查询方式更具有实时性,不需要考虑定时轮询频率的问题,可有效消除CPU轮询开销,大大提高了I/O效率,是现代计算机中普遍采用的一项重要技术。

但也需要注意,中断控制方式也是有时间开销的,相对程序查询方式,它的额外开销是用于进程调度的两次上下文切换时间以及中断服务程序本身的开销,其提高I/O效率的前提是这些额外开销小于设备准备时间,当设备准备数据时间较长的时候是没有问题的。

但对于极高速外部设备,设备准备数据的时间很短,当这个时间比两次上下文切换加中断服务的开销还短时,使用中断控制方式的效率反而比忙等待轮询方式的效率更低,中断就会成为瓶颈。所以程序查询方式并不一定只适合慢速设备,在一些高速设备中也被普遍采用,例如最新的NVMe SSD硬盘在处理同步I/O时,就不再采用中断控制方式,而是采用程序查询方式进行数据交互。

假设进程P执行了printf(”darkmoon“),下面是通过系统调用请求打印这串字符的全过程解析:

1746090811355-2837005d-6ab7-4930-be74-6c37cbd59bb2.png

1746091074937-17860b97-b141-4e28-89f4-b6aa614f4151.png

copy_string_to_kernel(strbuf, kernelbuf,n)://将字符串复制到内核缓冲区
enable_interrupts ();  //开中断,允许外设发出中断请求
while (printer_status != READY);//等待直到打印机状态为“就绪”
{
    *printer_data_port=kernbuf[il;//向数据端口输出第一个字符
    *printer_control_port=START;//发送“启动打印”命令
    scheduler ()://阻塞用户进程P,调度其他进程执行
}

详解:

copy_string_to_kernel(strbuf, kernelbuf,n)://将字符串复制到 内核缓冲区

前面我们说了,进程P执行了系统调用进入内核态之后,仅仅发生了特权级和堆栈的切换,但是地址空间没有变,此时并没有切换进程,在执行完这条指令之后,会将我们想要打印输出的“darkmoon”复制到内核缓冲区,以便多进程共享,至于为什么,后面我们便会知道原因;

1746084832365-a2e7b4ff-a9d5-4819-9fd2-694455b556d2.png

while (printer_status != READY);//等待直到打印机状态为“就绪”

通过读取打印机的 设备控制器里的状态寄存器 (例如1表示就绪、0表示未就绪)读取状态;(也叫IO端口)

1746087504655-fdd36826-c24c-4c95-ad5c-1e098b694ecb.png

*printer_data_port=kernbuf[il;//向数据端口输出第一个字符

CPU通过执行 设备驱动程序 从 内核缓冲区 读取字符串的第一个字符“d”,先读到CPU里的 通用寄存器 ,然后执行驱动程序里的 I/O指令 将其写入设备控制器里的 数据寄存器(I/O端口)

1746087752218-7264568a-0c05-4c96-a90a-f17f9ec493e6.png

*printer_control_port=START;//发送“启动打印”命令

CPU通过执行 设备驱动程序 向打印机设备控制器里的 控制寄存器 发送“启动打印”命令

1746088097243-1119a71a-24ea-4e10-b9c7-c3b6782878bd.png

Note

注意:设备驱动程序在往打印机控制器的端口写数据(访问I/O端口)的方式有两种

  • 如果主存和IO端口是独立编址,需要通过I/O端口号访问相应的设备寄存器,将通用寄存器的信息写入IO端口执行out指令、将IO端口的信息读入通用寄存器则用in指令;这两个IO指令都是特权指令,运行在内核态;
  • 如果主存和IO端口是统一编址,那么IO端口将被映射到内存物理空间,通过Load/Store的统一访存指令便可完成IO操作

设备驱动程序将对I/O端口的具体访问细节封装成供外部访问的write()接口,打印机设备的中断处理程序只需要调用write()接口即可实现将内核缓冲区中的数据写入IO端口(即打印机设备控制器的数据寄存器)。

scheduler () ;//阻塞用户进程P,调度其他进程执行

由于当前进程P主动发起I/O,需要等打印机打印完这个字符串之后P进程才能继续运行,因此CPU此时执行 调度程序 ,修改当前进程P的状态由 运行态 变为 阻塞态 (注意,这是 主动阻塞 ),然后将P挂入阻塞队列;

调度器从就绪队列选择一个进程Q,修改它的PCB,将其从就绪态修改为运行态,之后执行进程上下文切换(切换地址空间(例如页表基址寄存器的值等)、当前CPU上下文(断点、现场)等),进程Q上处理机

在这之后,CPU执行进程Q,与此同时,打印机也在工作,当打印机取出设备控制器里数据寄存器的字符“d”打印后,控制器里的IO控制逻辑会发出一个 中断请求信号 给CPU,CPU此时正在执行进程Q,当执行完一条指令去检查是否有中断,然后收到中断信号后,切换特权级,执行中断隐指令(关中断、保存断点、中断服务程序寻址),然后跳转到“字符打印”中断服务程序执行,如下;

1746089046475-fa324898-1b11-46c2-af96-8e9d776c92df.png

if (n==0) {//若字符串打印完,则
    unblock_user ();//用户进程P解除阻塞,P进就绪队列
}else{
    *printer_data_port=kernelbuf[i];//向数据端口输出一个字符
    *printer_control_port=START;//发送“启动打印”命令
    n=n-1;//未打印字符数减1
    i=i+1;//下一个打印字符指针加1
    acknowledge_interruptO://中断回答(清除中断请求)
    return_from_interruptO://中断返回

由此可见,字符串“darkmoon”的第一个字符打印是在sys_write系统调用服务例程的控制下进行的,剩下的字符打印都是由字符打印中断服务程序控制进行;

在执行该中断服务的过程中,CPU仍然运行在进程Q的环境之中,地址空间也是进程Q的,但是CPU却要执行进程P发起的打印任务;如果之前没有把要打印的字符串复制到内核缓冲区,而是放在进程P的用户地址里面,那么此时就没办法拿到这个字符串了,为什么放在内核缓冲区就可以解决这个问题,因为每个进程都有内核区域的同映射,因此可以利用内核空间作为中介来进行数据的传递,通常我们在内核中分配一个多进程可读写的内存区域作为内核缓冲区;

1746090131845-dcb87d25-b6d3-42a4-a449-ba228fc46167.png

后面剩余的字符串打印都是由中断服务程序负责控制的,每次执行的时候先检查是否打印结束,如果没有,再从内核缓冲区取出该打印的字符先放入通用寄存器再送入IO端口,然后发送”启动打印“命令,再中断返回,继续执行进程Q;

进程Q继续执行,收到中断信号再去处理,周而复始,直到字符串全部打印结束,这时候中断服务程序会去修改进程P的状态,由阻塞态变为就绪态,将其从阻塞队列取出,放入就绪队列;然后返回继续执行进程Q;

这一阶段的过程如图所示

1746090559548-be64116a-2ada-4bc2-a88a-5f397ebd873c.png

之后,如果进程Q释放了处理机,并且调度器从就绪队列选择了进程P上处理机,那么P会执行系统调用的最后阶段,返回用户态继续执行;

1746091326566-794c0b56-cd04-46fb-866c-813e1676e514.png

1746095362660-4d471684-af77-4461-b9a5-a9dc654f26ec.png

如图,是对上面这种IO工作方式的一个描述,尝试解答一下以下问题

  1. 图中的紫色段、黑色段、蓝色段都分别在执行什么操作?
  2. a点进程P执行了什么操作?
  3. b点进程处于什么状态?发生了什么?是在用户态还是内核态下执行的?
  4. 上面哪些时间段,CPU和外设是并行执行的?
  5. c点发生了什么?d呢?
  6. e点和f点分别在干啥?
  7. 哪些时间节点,CPU执行关中断?
答案
  1. 紫色段外设在执行打印操作,即打印机从设备控制器里的数据寄存器取出字符并打印;黑色段在执行中断隐指令(关中断、保存断点、中断服务程序寻址);蓝色段在执行字符打印中断服务程序;
  2. a点发起系统调用,然后查找系统调用表,执行sys_write( )系统调用服务例程;
  3. b点启动外设打印第一个字符,与此同时,修改进程P的状态由运行态变为阻塞态,ab段是在内核态下执行的,在a点发起系统调用执行trap指令,之后执行关中断、保存断点、中断服务程序寻址,找到了system_call系统调用服务程序开始执行;
  4. 图中的绿色段CPU与外设都是并行执行的
  5. c点打印机打印结束,发来中断请求信号,进程Q在执行完一条指令后响应该中断,因此cd段在执行中断隐指令;d点找到了字符打印的中断服务程序的入口地址,之后CPU开始执行该中断服务程序;
  6. 在执行字符打印中断服务程序的过程中,检测到字符串没有打印结束,在e点将字符从内核缓冲区取出通过通用寄存器传送到打印机控制器里的数据寄存器,同时发出字符打印的命令,让外设工作;f点中断返回,cpu由内核态切换为用户态,进程Q继续执行;
  7. a点由于执行trap指令会关中断、c点响应中断请求信号后会关中断 ;

外设工作(本例子中,打印机从IO接口里的数据寄存器取出字符打印)

1745158083574-95954169-adb1-4bf6-ae34-16a86c53568a.png

【2023-46】(8分)进程P通过执行系统调用从键盘接收一个字符的输入,已知此过程中与进程P相关的操作包括:①将进程P插入就绪队列;②将进程P插入阻塞队列;③将字符从键盘控制器读入系统缓冲区;④启动键盘中断处理程序;⑤进程P从系统调用返回;⑥用户在键盘上输入字符。以上编号①~⑥仅用于标记操作,与操作的先后顺序无关。请回答下列问题。

(1) 按照正确的操作顺序,操作①的前一个和后一个操作分别是上述操作中的哪一个?操作⑥的后一个操作上述操作中的哪一个?

(2) 在上述哪个操作之后CPU一定从进程P切换到其他进程?在上述哪个操作之后CPU调度程序才能选择进程P执行?

(3) 完成上述哪个操作的代码属于键盘驱动程序?

(4) 键盘中断处理程序执行时,进程P处于什么状态?CPU处于内核态还是用户态?

  1. 进程P发起系统调用
  2. 执行system_call系统调用服务程序
  3. 执行sys_write系统调用服务例程
  4. 将字符串复制到内核缓冲区
  5. 将字符串的第一个字符从内核缓冲区写入打印机控制器的数据端口
  6. 将进行P插入阻塞队列
  7. 从就绪队列选择进程Q执行
  8. 打印机打印完第一个字符
  9. 启动字符打印中断处理程序
  10. 将进程P插入就绪队列
  11. 继续执行进程Q
  12. Q时间片到期
  13. 调度器选择P上处理机
  14. P从系统调用返回

【2010-32】本地用户通过键盘登录系统时,首先获得键盘输入信息的程序是( )。

A. 命令解释程序

B. 中断处理程序

C. 系统调用服务程序

D. 用户登录程序

【2024-31】键盘中断服务例程执行结束时,所输入的数据存放位置是

A. 用户缓冲区

B. CPU 中的通用寄存器

C. 内核缓冲区

D. 键盘控制器的数据寄存器

DMA 方式

直接内存访问(Direct Memory Access,DMA)就是为了减少I/O过程中CPU用于实际传输的开销而引入的。该方式在总线上设置了DMA控制器电路(DMAC),由DMAC临时接管总线代替CPU控制外部设备和内存之间的批量数据交换;CPU不再参与实际数据传输过程,数据直接通过系统总线在外部设备和内存之间进行交换,完全消除了程序查询和程序中断控制方式中CPU进行实际数据传输的开销,系统效率得到了巨大提高。

DMA方式中由DMA控制器暂时接管总线控制外部设备与内存之间的直接数据交换, 数据无须由CPU寄存器中转。在DMA传送前CPU需要访问DMAC接口以设置DMA传输参数,具体包括主存地址、数据块长度、传输方向等;然后向设备的I/O接口发送命令和参数来启动设备。传输过程中CPU可以继续执行其他程序,设备需要进行DMA操作时由DMAC向CPU申请总线控制权用于数据传输;一个数据块传送结束后,DMAC会通过中断方式请求CPU对数据缓冲区和DMA控制器进行后处理。

DMA方式主要用于高速设备的块数据传输,常见的磁盘、显卡、网卡、声卡均支持DMA访问,这类设备的数据传输多采用数据块方式。DMA甚至还可以用于内存数据的内部搬移,这种操作经常发生。如果利用CPU程序进行大批量的内存数据搬移,需要经过寄存器中转,会消耗大量的CPU资源,采用DMA方式则可以大大提高搬移效率。DMA方式是程序中断传送技术的进一步发展,在传输结束阶段复用了中断技术,它在硬件逻辑机构的支持下,以更快的速度、更简便的形式传送数据,和中断技术存在如下明显的区别。

  1. 二者均采用了“请求-应答”机制,但中断技术中请求的是CPU时间,响应的时机是指令周期结束时刻;DMA方式请求的是总线控制权,响应时机是任何一个机器周期结束的时刻(或一个总线事务后,一个总线周期后这些说法都可以)。
  2. 中断技术中通过CPU执行程序进行实际数据传送,存在程序执行现场的保护和恢复问题;而DMA方式依靠额外硬件来实现数据传输,其不改变CPU现场,不影响系统性能。
  3. DMA方式仅仅用于数据的传输;而中断技术不仅可以实现数据传输,还可以用于处理各种随机事件,提高计算机的灵活性。
内存争用问题

DMA 控制的关键是 DMAC 占领接管控制权还是外部设备与主存交换数据时,CPU 仍执行主程序。虽然大多数时候 CPU 执行程序需要的指令和数据都在缓存中获取可以解决,但可能存在 DMAC 与 CPU 争用主存的问题。为避免由此而导致的内存访问冲突,可以采用 DRAM 刷新控制器或与 CPU 的内存争用同样的方法,常用的方式有停止 CPU 访问内存、DMAC 与 CPU交替访问内存及时钟周期有3种方式。

停止CPU访问内存

核心思想是:DMA优先,一旦开始,不传完不罢休。

1760463593033-97d89ce2-8dc7-41e5-82ad-e540a5f737af.png

  • 工作流程:
  • DMA请求: 当需要传输一个完整的数据块时,DMAC向CPU发出总线请求。
  • CPU放弃总线: CPU在完成当前指令(或总线周期)后,响应DMA的请求,释放对地址总线、数据总线和内存控制总线的控制权,并进入暂停或等待状态。
  • DMA独占传输: DMAC完全接管总线,在连续的多个内存周期内,将整个数据块从设备一次性地传输到主存(或反之)。
  • 归还总线: 整个数据块传输完毕后,DMAC撤销总线请求,将总线控制权交还给CPU。CPU从暂停状态中恢复,继续执行程序。
  • 优点:
  • 控制简单: 逻辑实现最简单,总线的请求、建立和归还只需要一次。
  • 数据传输率最高: 在DMA传输期间,数据是连续不断地流动的,达到了设备和内存能支持的最高传输速率,非常适合高速设备的大块数据传输。
  • 缺点:
  • CPU响应中断延迟: 在DMA传输期间,CPU处于“与世隔绝”的状态,无法响应任何中断请求,这会严重影响系统的实时性。
  • CPU效率低: 即使CPU当前执行的程序不需要访问内存(例如,指令和数据都在Cache中),它也被强制暂停,CPU的时间被白白浪费。
  • 适用场景: 适用于对数据传输速率要求极高,且可以容忍CPU短时间无响应的场景,例如系统刚启动时从磁盘加载操作系统核心。
DMA与CPU交替访问内存

核心思想是:将时间片一分为二,CPU和DMAC各用一半,互不干扰。

1760463622999-c1c8b311-e772-4312-87a4-ffbb308787d4.png

  • 工作流程:
  • 周期划分: 将每个内存工作周期固定地划分为两个部分(T1和T2)。
  • 固定分配: 强制规定CPU只能在T1时间片内访问内存,而DMAC只能在T2时间片内访问内存。
  • 并行工作: CPU和DMAC在一个大的 内存工作周期内,各自利用自己的时间片访问内存,实现了分时复用。
  • 优点:
  • 无需总线请求: 由于访问时间是预先分配好的,DMAC不需要向CPU申请、等待和归还总线,省去了总线控制的开销。
  • CPU不受影响: 从CPU的角度看,它感觉不到DMA的存在,可以连续工作。
  • 缺点:
  • 硬件代价高: 需要复杂的时钟和内存控制逻辑来划分和同步周期。
  • 资源浪费:
    • 当CPU不需要访存时,分配给它的T1时间片被浪费。
    • 当DMAC没有数据要传输时,分配给它的T2时间片也被浪费。
    • 这种方式实质上导致内存总带宽减半,因为双方都只能用一半的时间。
  • 适用场景: 在理论上很完美,但因其硬件复杂且效率不高,在实际中应用较少。
周期挪用

核心思想是:按需分配,DMA只在需要时“借用”一个存储周期。

1760463646170-a7783091-f4a2-4b3e-9316-fa7d6a9b6a53.png

  • 工作流程:
  • DMA请求: 当设备准备好一个字(或字节)的数据需要传输时,DMAC向CPU发出总线请求。
  • CPU暂停一拍: CPU在在当前机器周期结束时(或者说一个总线事务/一个总线周期后),立即释放总线控制权。
  • DMA传输一个字: DMAC获得总线后,只占用一个存储周期,快速地完成这一个字的数据传输。
  • 立即归还: 传输完成后,DMAC马上释放总线,CPU立即恢复工作。这个过程就像DMAC从CPU的指令流中“窃取”了一个存储周期。

DMA操作不会修改CPU寄存器,所以不会出现现场保护的问题。如果周期挪用期间CPU不访问内存,则这种方式对CPU的执行没有性能影响;如果周期调用恰好也访问内存,即形成访存冲突,此时,DMA优先访问内存。周期挪用已成为DMA传输方式的主要方法。

Info

注意: 它只挪用了CPU的一个存储周期来完成数据传输,但由于总线请求、仲裁和归还的额外开销,完成这次挪用操作的整个过程实际上需要花费2到5个存储周期的时间。

DMA 控制器

1760350164290-b41204d4-8538-4c43-a21e-518459bf485c.png1760350164048-a2ab0730-2f58-43bc-b10b-cc01c59641ef.png

注意:形似左图的这种 DMA 结构其实有很多错误,比如

  1. 图中将“设备”直接连接到了DMA控制器。这是一个根本性的错误。物理设备(如硬盘、网卡)需要一个专门的设备控制器来处理其复杂的底层协议、时序和数据缓冲。DMA控制器是一个通用的“搬运工”,它无法直接理解和操作成千上万种设备的具体细节。它沟通的对象应该是设备的“管理员”——设备控制器,而不是设备本身。
  2. 图中画出了数据从“设备”直接进入DMA控制器的“数据缓冲寄存器”,然后再通过数据总线送到主存。这种模式虽然存在(称为“块传送”或“存储转发”模式),但它不是最高效、最常用的“周期窃取”模式。

袁春风DMA控制器示意图谭志虎DMA示意图

DMA 控制器的基本结构如图所示,内部主要包括各类寄存器、DMA 控制逻辑等,其各部分的作用分别如下。

  1. 地址计数器(主存地址寄存器),它用于存放交换数据的内存地址。在 DMA 预处理阶段由 CPU 设置,每次 DMA 传送后自动修改 (递增或递减),指向下一个内存单元。
  2. 字计数器,它用于记录数据块的长度,也在预处理阶段设置。传送开始后,每传送 1 个字或字节就自动减 1。当计数值为 0 时,数据传送完毕,发出 DMA 中断请求信号。
  3. 数据缓冲寄存器 (DBR),DMAC作为从设备时其可用来接收 CPU 传输的数据,DMAC 作为主设备时其可以用来暂存传输数据。当然,若不经过该寄存器直接通过数据总线实现设备和内存之间的数据交换,则性能更好。

DMA的两种主要数据传送方式:

  1. 存储器-存储器传送(需要DBR):数据先从I/O设备读入DMAC的DBR,再从DBR写入主存。需要两次总线操作,速度慢。
  2. 周期窃取模式:DMAC同时把内存地址送到地址总线,并发出I/O读信号。I/O接口收到信号后直接把数据送到数据总线,内存控制器同时监听到总线上的数据并写入。数据“飞过”DMAC,不进入其内部,一次总线操作就完成,性能好。
  1. 命令寄存器,它用于接收 CPU 的控制命令。
  2. 状态寄存器,它负责向 CPU 反馈 DMA 控制器状态。
  3. DMA 控制逻辑,它包括控制和时序电路,以及状态标志,用来修改内存地址计数器和字计数器,指定数据传输方向,并对 DMA 请求信号和 CPU 响应信号进行协调和同步;控制逻辑还应该支持中断机制,一组数据交换完毕时,向 CPU 发出 DMA 中断请求,通知 CPU 进行结束处理。

图中 DMAC 作为一个 I/O 设备连接在系统总线上,既可以充当从设备,也可以充当主设备,注意在系统总线上可能有多个 DMAC。在现代个人计算机中,CPU、DMAC、I/O 接口、内存均通过系统总线相连,并不存在所谓的专用数据通路连接设备和内存。

  • 在预处理(配置)阶段,CPU是主设备,DMAC是从设备。CPU通过执行OUT之类的指令,像访问普通I/O端口一样,向DMAC的命令/地址/字计数等寄存器写入配置信息。
  • 在数据传输阶段,DMAC是主设备,CPU反而成了“旁观者”。DMAC主动控制总线,在内存和I/O接口之间搬运数据。

DMAC 需要申请总线控制权时,会通过系统总线中的 HOLD 信号向 CPU 发出总线使用请求。CPU 中的总线控制器如果允许,可以向 DMAC 发出总线授权信号 HLDA。支持 DMA 传输的 I/O 设备通过 DREQ (DMA 请求)、DACK (DMA 应答) 两条单独的连线与 DMAC 相连。一个 DMAC 支持多个通路,每个通路包括各自独立的内存地址寄存器和字计数器等,可以同时为多个设备提供 DMA 服务。

系统总线(地址、数据、控制总线)是所有设备共享的公共通道。而DREQ/DACK是DMAC用来管理它所服务的那些特定I/O接口的“私有通道”;这两条线通常不属于系统总线,而是DMAC与I/O接口之间的专用控制线。

图 中 DMAC 又称为第三方 DMA,也就是设备和内存之间的数据交互需要通过第三方 DMAC 进行控制,当 DMAC 上连接的设备过多时,第三方 DMAC 会成为性能瓶颈。现代总线技术普遍支持总线主控技术,I/O 设备也可以作为主设备获得总线控制权,所以 DMAC 逐渐集成到 I/O 接口中,为专属设备进行服务,这种 DMAC 方式称为第一方 DMA。

DMA 传输流程

1760611300859-843933db-b1ec-4a9f-86e4-eda08588828e.png

1. 预处理阶段(DMA 准备阶段)

在用户进程发起I/O请求(如读文件)后,操作系统会调用相应的设备驱动程序,由CPU执行以下一系列初始化操作:

第1步:CPU配置DMA控制器

在此阶段,CPU是主设备,DMA控制器(DMAC)是从设备。CPU通过执行I/O指令,将数据传输所需的全部参数写入到DMAC内部的各个寄存器中。

  • ① 设置内存地址:CPU计算出数据在主存中的起始地址,并将此地址写入DMAC的 主存地址寄存器(AR)。
  • 如果是输入操作(设备→内存),CPU会先在内存中申请好一块缓冲区。
  • 如果是输出操作(内存→设备),CPU要确保数据已在内存中准备好。
  • ② 设置传输长度:CPU确定要传输的数据总量(如多少个字节或字),并将这个数值写入DMAC的 字计数器(WC)。
  • ③ 设置传输方向:CPU通过设置DMAC 控制/命令寄存器 中的特定标志位,来指明数据是从设备传输到内存(读内存/写设备),还是从内存传输到设备(写内存/读设备)。

第2步:CPU启动I/O设备

仅仅配置好DMAC是不够的,还需要通知具体的I/O设备开始工作。

CPU向I/O接口(设备控制器)发送启动命令。这个命令包含了设备需要的信息,例如要读取的磁盘扇区号、要操作的设备地址等。这些信息会被写入设备控制器自己的寄存器中(如设备地址寄存器DAR)。

第3步:CPU下达“开始”指令并“放手”

所有参数设置完毕,设备也已启动,CPU会执行最后一步准备工作:

  • 向DMAC的控制寄存器写入一个“启动DMA”的命令位。这相当于告诉DMAC:“所有信息都给你了,你可以开始接管了!”
  • 完成这一系列设置后,操作系统会将发起I/O请求的当前进程挂起(阻塞),因为它需要等待数据传输完成。
  • 同时,CPU调度程序会从就绪队列中选择另一个进程投入运行。这样,在I/O设备准备数据和DMA进行传输的漫长时间里,CPU资源不会被浪费,而是被充分利用于执行其他计算任务。

预处理阶段结束时,我们达到了以下状态:

  1. DMA控制器已经明确知道了本次任务的所有细节:从内存的哪个地址开始,传输多少数据,以及传输的方向。
  2. I/O设备已经收到了指令,开始准备数据(例如,硬盘开始移动磁头寻道)。
  3. CPU已经完全脱身,正在为其他进程服务,实现了CPU与I/O操作的并行。

至此,万事俱备,只等设备准备好第一块数据,然后通知DMA控制器,正式进入数据传输阶段。

2. 数据传输阶段(以最常见也是最常考的周期挪用为例)

这个阶段是DMA工作的核心,完全由硬件(DMA控制器)主导,CPU在此期间可以“袖手旁观”,执行其他任务。我们可以把整个阶段看作是一个由DMAC指挥的、针对单个数据字的、高速循环的“搬运”过程。

这个阶段的本质是一个循环,直到数据块全部传输完毕。以下是循环中每一次(传输一个字)所发生的详细步骤:

第1步:设备就绪,发出请求

  • I/O设备在收到了预处理阶段CPU发来的启动命令后,便开始工作(如硬盘寻道并读取数据)。当它成功准备好一个数据字(或字节)并放入其内部的缓冲寄存器后,它会通过专用的DREQ(DMA Request) 控制线向DMA控制器发出DMA 请求。
  • 这个信号的含义是:“我这里有一份数据准备好了,可以开始传送了!”

第2步:DMAC申请总线

  • DMAC接收到DREQ信号后,立即行动。它通过HOLD(或BREQ)总线信号向CPU发出 总线请求。
  • 这个信号的含义是:“CPU,请暂停一下,我需要借用系统总线一个周期来搬运数据。”

第3步:CPU授权总线

  • CPU在执行完当前的机器周期(确保总线是空闲的)或一个总线事务后,会响应DMAC的请求。
  • CPU会断开自己与总线的连接(使其总线驱动器进入高阻态),并发出HLDA (Hold Acknowledge) 信号作为回应。
  • 这个信号的含义是:“好的,总线现在归你了,用吧!”

第4步:DMAC主导数据传输

  • DMAC收到HLDA信号,确认自己已成为总线主设备。它立即开始在一个存储周期内完成以下所有操作:
  • 发出地址:DMAC将内部主存地址寄存器(AR) 中的地址放到 地址总线上,指定数据要被写入内存的哪个位置。
  • 发出控制信号:DMAC向控制总线发出相应的控制信号(例如,内存写MEMW 和 I/O读IORD 信号)。
  • 响应设备:DMAC通过DACK (DMA Acknowledge) 信号线回应发出DREQ的设备。这个信号的含义是:“总线已就绪,立刻把你的数据放到数据总线上!”
  • 数据上路:收到DACK后,I/O接口(设备控制器)立即将其数据缓冲寄存器中的数据字放到数据总线上。
  • 内存写入:主存的内存控制器检测到地址总线上的地址和控制总线上的写命令,便将数据总线上的数据写入到指定的内存单元中。

第5步:更新状态并归还总线

  • 在完成这一个字的数据传输后,DMAC会立即进行内部处理:
  • 主存地址寄存器(AR) 自动加1(或减1),为下一次传输做好准备。
  • 字计数器(WC) 自动减1,表示还需传输的数据量又少了一个。
  • 同时,DMAC撤销HOLD请求,将总线控制权立即归还给CPU。CPU可以继续执行一两个周期,直到下一次DREQ的到来。这就是“周期窃取”的精髓。

循环与结束

  • 循环往复:上述1到5步的过程会不断重复。I/O设备准备好下一个字,再次发出DREQ,DMAC再次“窃取”一个周期来传输它,周而复始。
  • 传输结束:DMAC在每次传输后都会检查字计数器(WC)。当WC的值最终减为0时,意味着预设的数据块已全部传输完毕。
  • 发出中断:此时,DMAC会通过INTR信号线向CPU发送一个中断请求。这个中断信号会告知CPU:“任务已完成!”

至此,数据传输阶段宣告结束,流程进入最后的DMA结束阶段,CPU将响应这个中断,进行后续处理。

3. 后处理阶段(DMA 结束阶段)

第1步:DMAC发出中断请求

这是整个后处理阶段的起点。DMAC通过向CPU发送一个中断请求信号 (INTR) 来主动报告。触发这个中断的原因有两个:

  • 正常完成:DMAC内部的字计数器(WC)递减至0,表示所有预设的数据都已成功传输。
  • 异常中止:在传输过程中发生硬件故障(如内存校验错误、设备无响应等)。

第2步:CPU响应中断并保存现场,转向中断服务程序

第3步:CPU检查DMA状态 :进入中断服务程序后,CPU通过执行I/O指令,读取DMAC内部的状态寄存器。这个寄存器中包含了此次DMA操作的最终结果,例如:

  • 一个“传输完成”标志位是否被设置。
  • 一个“发生错误”标志位是否被设置。
  • 具体的错误类型代码(如果有)。

第4步:CPU根据状态进行决策与处理 :这是后处理阶段的核心,CPU根据读取到的状态进行处理:

  • 情况A:传输成功
  • 唤醒等待进程:操作系统会找到当初因为发起这次I/O请求而被阻塞的那个进程。
  • 将其状态从“阻塞/等待态”修改为“就绪态”,并把它移入进程就绪队列。
  • 这意味着该进程现在万事俱备(数据已在内存中),只等CPU调度程序下一次选中它,就可以继续向下执行了。
  • 情况B:传输失败
  • 执行错误处理程序:操作系统会调用相应的错误处理例程。
  • 这可能包括:记录错误日志、尝试重新传输(如果错误是可恢复的)、或者放弃操作。
  • 通知原进程:通过某种机制(如设置一个错误码),告知发起I/O的进程本次操作失败。同样,该进程也会被唤醒并移入就绪队列,但当它恢复执行时,会立即发现I/O操作返回了一个错误,从而进入自己的错误处理逻辑。

第5步:恢复现场并返回

中断服务程序执行完毕后,CPU会执行中断返回指令 (IRET)。

  • 它会将之前 保存到堆栈的信息全部恢复到CPU寄存器中。
  • CPU便无缝地回到了之前被中断的那个进程的执行点,就好像什么都没发生过一样,继续它之前的工作。

1760702081355-9fd203cc-f448-403a-86cf-73fa8e3c4ef4.png

Info

上述 DMA 传输的预处理过程就是在系统调用服务例程里执行的;传输阶段全程由 DMA 硬件负责执行;后处理阶段发出 DMA 中断请求后执行上图中的 DMA 结束中断服务程序;

上图对应的是输出过程,如果是输入过程的话,当前进程在被 dma 结束中断服务程序唤醒后,在被调度程序选中上了处理机后,会继续执行系统调用服务例程把数据从内核缓冲区复制到用户空间;

注意,一般来说,DMA 控制器里面的主存地址寄存器记录的是主存物理地址,如果一个进程执行 read 系统调用从磁盘读文件,会先把数据读到内核区域再复制到用户空间,因为这些数据可能跨越好几个页面,用户空间的页面一般都是离散存放的;不过像是缺页异常处理这种,因为需要调入的是一整个页面,因此可以直接写入到对应用户空间的页框中。

在采用周期挪用DMA方式传送数据块的过程中,下列叙述中,错误的是?

A. DMA控制器每准备好一个字的数据,便会请求挪用一个总线周期。

B. CPU在执行指令期间,若发现DMA总线请求,会立即暂停当前指令的执行,让出总线。

C. 在整个数据块传送完成前,CPU可以与DMA控制器分时交替地访问主存。

D. 数据块传送结束时,DMA控制器会通过一个中断信号通知CPU。

解析

答案 B

A. 正确。 这是“周期挪用”方式的定义。I/O设备每准备好一个字(或字节),DMA控制器就向CPU请求一个总线周期来传送这一个字的数据。

B. 错误。 CPU对DMA请求的响应不是在指令执行期间的任意时刻,而是在一个总线周期(或称存取周期、机器周期)的结束时。如果CPU正在通过总线访问内存,它必须完成这次访存操作后,才能让出总线给DMA控制器使用。它不会“立即暂停当前指令的执行”,因为一条指令可能包含多个总线周期。而中断请求是在一条指令周期的末尾响应。

C. 正确。 由于DMA每次只“偷走”一个总线周期来传送一个字,在传送的间隙,CPU仍然可以控制总线并访问主存。因此,在宏观上,CPU和DMA控制器是分时交替使用总线的,这保证了CPU不会被长时间阻塞。

D. 正确。 无论采用何种DMA方式(周期挪用、停止CPU或交替访存),当整个数据块(由字计数器决定)传送完毕后,DMA控制器都会向CPU发出中断请求,通知CPU传送任务已完成,以便进行后处理。

DMA方式 vs. 中断I/O方式
对比维度 DMA 方式 中断I/O 方式
核心思想 以存储器为核心,CPU将数据传输任务外包给专业硬件。 以CPU为核心,CPU亲自处理每一次数据传输请求。
数据传送的主体 硬件 (DMA控制器)。CPU不参与具体的数据传送过程。 软件 (CPU执行中断服务程序)。每一个字节/字都需经过CPU。
CPU介入程度 低。仅在“预处理”(初始化参数)和“后处理”(中断响应)阶段介入。 高。在整个数据传输过程中,CPU需要为每一个数据单位的传送执行一次中断服务程序。
请求的对象 请求总线控制权。DMAC向CPU请求的是对系统总线的临时使用权。 请求CPU处理时间。设备请求的是中断CPU,让CPU来为自己服务。
响应时机 在一个总线周期后。只要CPU当前不使用总线,DMAC就可以“见缝插针”地获得总线,响应非常快。 在一个指令周期后。CPU必须执行完当前指令,才能响应中断请求,响应相对较慢。
对CPU执行的影响 影响极小。在“周期窃取”模式下,仅使CPU暂停一个存储周期,不中断现行程序,也无需保护和恢复现场。 影响大。完全中止当前程序的执行,需要完整地保护现场、转去执行中断服务、再恢复现场,开销很大。
CPU与外设并行度 高。CPU在执行程序的同时,DMAC可以并行地进行数据传输。 低。CPU执行中断服务程序时,无法执行主程序,并行性体现在设备准备数据期间。
适用设备 适用于高速设备的大批量(块)数据传输,如磁盘、网卡。 适用于中、低速设备的少量数据传输,如键盘、鼠标。
功能范围 功能单一,仅用于成块数据的快速输入/输出。 功能广泛,除了数据交换,还能处理各种异常事件和突发状况(如时钟中断、电源掉电)。
优先级 优先级高。当DMAC和CPU同时要访问主存时,DMA优先(总线控制权),以保证高速设备的数据不丢失。 优先级低。程序中断方式的优先级低于DMA方式。

补充:在用 DMA 方式进行硬盘等高速设备的数据传输过程中,也要用到程序查询和中断 I/O 方式

1760625660474-708ab62f-e95b-4480-855b-57688d555940.png

  1. 首先, 进程 P₁ 采用程序查询方式设置传送参数, 通过执行相应的指令对有关参数寄存器进行初始化;
  2. 然后 CPU 执行 I/O 指令发出“寻道”命令到磁盘控制器, 由磁盘控制器控制磁盘驱动器开始移动磁头, 同时, CPU 切换到其他进程(如 P₂)执行; 当磁盘完成寻道操作后, 向 CPU 发出“寻道结束”中断请求;
  3. CPU 响应并处理该中断请求, 中止正在执行的进程 P₂, 在中断服务程序中通过执行 I/O 指令发出“查找扇区”命令到磁盘控制器, CPU 启动“查找扇区”命令后, 返回被中止的进程 P₂ 执行; 当磁盘完成扇区查找操作, 就向 CPU 发出“查找结束”中断请求;
  4. CPU 响应并处理该中断, 又一次中止正在执行的进程 P₂, 然后在中断服务程序中启动进行 DMA 传送, 由 DMA 控制器控制数据在主存和磁盘之间进行数据传送;
  5. CPU 启动 DMA 传送后, 又回到被中止的进程 P₂ 继续执行, 直到 DMA 传送结束; 此时, 由 DMA 控制器发出“DMA 结束”中断请求, CPU 响应并处理该中断请求, 对传送的数据进行校验等后处理。

【2013-22】下列关于中断I/O方式和DMA方式比较的叙述中,错误的是( )。

A. 中断I/O方式请求的是方式请求的是CPU处理时间,DMA方式请求的是总线使用权

B. 中断响应发生在一条指令执行结束后,DMA响应发生在一个总线事务完成后

C. 中断I/O方式下数据传送通过软件完成,DMA方式下数据传送由硬件完成

D. 中断I/O方式适用于所有外部设备,DMA方式仅适用于快速外部设备

解析

答案:D

B. 正确。CPU在每条指令执行周期的末尾检查中断请求。而DMA请求的是总线,CPU只要在当前的总线周期(或称机器周期)结束后,发现总线空闲,就可以把使用权让给DMA,响应比中断更快。

C. 正确。中断方式的数据传送是通过CPU执行中断服务程序(软件)中的I/O指令来完成的。DMA方式下,数据传送由DMA控制器(硬件)直接控制。

D. 错误。这句话错在过于绝对。中断I/O方式虽然可以用于各种设备,但对于速率极高的设备,频繁的中断会严重拖累CPU性能,使其变得不适用或效率极低。反之,DMA方式虽然是为高速设备设计的,但理论上也可以用于低速设备,只是会造成资源浪费(大炮打蚊子)。因此,“中断适用于所有设备”这个说法是错误的。

【2017-32】系统将数据从磁盘读到内存的过程包括以下操作:

① DMA控制器发出中断请求

② 初始化DMA控制器并启动磁盘

③ 从磁盘传输一块数据到内存缓冲区

④ 执行“DMA结束”中断服务程序

正确的执行顺序是( )。

A. ③→①→②→④

B. ②→③→①→④

C. ②→①→③→④

D. ①→②→④→③

解析

答案:B

这是一个典型的DMA工作全流程。

  1. 预处理阶段:首先,CPU必须对DMA进行设置,告诉它数据要从哪里来、到哪里去、传多少。同时,CPU也要向磁盘发出命令,让它开始工作。这对应操作 ② 初始化DMA控制器并启动磁盘。
  2. 传输阶段:CPU去执行其他任务。磁盘准备好数据后,由DMA控制器主导,将数据一块一块地传输到内存。这对应操作 ③ 从磁盘传输一块数据到内存缓冲区。
  3. 结束阶段:当所有数据都传输完毕后,DMA控制器需要通知CPU工作已完成。它通过发送一个中断信号来实现。这对应操作 ① DMA控制器发出中断请求。
  4. 后处理阶段:CPU响应这个中断,执行相应的中断服务程序,进行数据校验、唤醒等待进程等收尾工作。这对应操作 ④ 执行“DMA结束”中断服务程序。
  • 结论:正确的顺序是 ② → ③ → ① → ④。

【2019-22】下列关于DMA方式的叙述中,正确的是( )。

Ⅰ. DMA传送前由设备驱动程序设置传送参数

Ⅱ. 数据传送前由DMA控制器请求总线使用权

Ⅲ. 数据传送由DMA控制器直接控制总线完成

Ⅳ. DMA传送结束后的处理由中断服务程序完成

A. 仅Ⅰ、Ⅱ

B. 仅Ⅰ、Ⅲ、Ⅳ

C. 仅Ⅱ、Ⅲ、Ⅳ

D. Ⅰ、Ⅱ、Ⅲ、Ⅳ

解析

答案:D

Ⅰ. 正确。设备驱动程序是运行在CPU上的软件,它负责执行I/O指令来初始化DMA控制器的各个寄存器(如内存地址、字计数器等)。

Ⅱ. 正确。当设备准备好一个数据字时,会通知DMA控制器,然后DMA控制器向CPU发出总线请求(HOLD/HRQ)。

Ⅲ. 正确。一旦获得总线使用权,DMA控制器就成为总线主设备,负责发出地址和控制信号,完成数据在设备和内存之间的传送。

Ⅳ. 正确。数据块传送完毕后,DMA控制器会向CPU发出中断请求,CPU响应该中断并执行中断服务程序进行后处理。

结论:Ⅰ、Ⅱ、Ⅲ、Ⅳ全部正确。

【2020-22】若设备采用周期挪用DMA方式进行输入和输出,每次DMA传送的数据块大小为512字节,相应的I/O接口中有一个32位数数据缓冲寄存器。对于数据输入过程,下列叙述中,错误的是( )。

A. 每准备好32位数据,DMA控制器就发出一次总线请求

B. 相对于CPU,DMA控制器的总线使用权的优先级更高

C. 在整个数据块的传送过程中,CPU不可以访问主存储器

D. 数据块传送结束时,会产生“DMA传送结束”中断请求

解析

答案:C

A. 正确。I/O接口的缓冲寄存器是32位(4字节)。在周期挪用方式下,每当这个缓冲区满了,设备就会通过DREQ通知DMA控制器,DMA控制器随即申请一次总线来传送这32位数据。

B. 正确。这是一个基本设计原则。为了防止高速设备的数据因来不及传送而丢失(数据覆盖),DMA的总线请求优先级通常高于CPU。

C. 错误。这是对“周期挪用”方式的误解。“周期挪用”的特点是DMA只在需要传送数据时“窃取”一个内存周期,在两次窃取之间的间隙,CPU完全可以正常访问主存储器。只有在“停止CPU”或“猝发模式”下,CPU才会在整个数据块传送期间被禁止访问主存。

D. 正确。当512字节的数据全部传送完毕(字计数器减为0),DMA控制器会向CPU发出中断请求,通知任务完成。

【2024-22】DMA 控制 I/O 方式下,设备的输入/输出由 DMA 控制器控制完成,此时,DMA 控制器控制的数据传输通路位于

A. CPU 和主存之间

B. CPU 和 DMA 控制器之间

C. 设备接口和主存之间

D. 设备接口和 DMA 控制器之间

解析

答案:C

A. CPU 和主存之间:这是CPU正常执行程序时的数据通路。

B. CPU 和 DMA 控制器之间:这是在DMA预处理阶段,CPU向DMA控制器写入参数时的通路。

C. 设备接口和主存之间:正确。DMA的核心目的就是建立一条绕过CPU的、在设备接口(控制器)和主存之间的直接数据通路。DMA控制器是这个通路的指挥者,但通路本身连接的是设备接口和主存。

D. 设备接口和 DMA 控制器之间:这是DREQ/DACK等控制信号的通路,或者在某些非“Fly-by”模式下,数据会暂存到DMA控制器,但这并不是最终的数据通路。最终的数据目的是主存。

【2022-44】(8分)假设某磁盘驱动器中有4个双面盘片,每个盘面有20000个磁道,每个磁道有500个扇区,每个扇区可记录512字节的数据,盘片转速为7200rpm(转/分),平均寻道时间为5ms,请回答下列问题。

(1) 每个扇区包含数据及地址信息,地址信息分为3个字段,这3个字段的名称格式什么?对于该磁盘,各字段至少占多少位?

(2) 一个扇区的平均访问时间约为多少?

(3) 若采用周期挪用DMA方式进行磁盘与主机之间的数据传送,磁盘控制器中的数据缓冲区大小为64位,则在一个扇区读写过程中,DMA控制器向CPU发送了多少次总线请求?若CPU检测到DMA控制器的总线请求信号时也需要访问主存,则DMA控制器是否可以获得总线使用权?为什么?

解析

(1)磁盘扇区的物理地址信息通常采用柱面-磁头-扇区 (Cylinder-Head-Sector, CHS) 格式来表示。

① 柱面号 (Cylinder): 柱面是指所有盘面上相同编号的磁道构成的圆柱。磁盘有20000个磁道,因此就有20000个柱面。为了能唯一表示这20000个柱面(从0到19999),需要的位数是 公式。

② 磁头号 (Head): 磁头号用于选定具体的某一个盘面。磁盘有4个双面盘片,共 公式 个盘面,对应8个磁头。为了能唯一表示这8个磁头(从0到7),需要的位数是 公式。

③ 扇区号 (Sector): 扇区号用于选定某个磁道上的特定一个扇区。每个磁道有500个扇区。为了能唯一表示这500个扇区(从0到499),需要的位数是 公式。

(2) 平均访问时间 = 平均寻道时间 + 平均旋转延迟时间 + 数据传输时间。

① 平均寻道时间 公式。

② 平均旋转延迟时间 这是磁头定位到目标磁道后,等待目标扇区旋转到磁头下方所需时间的平均值,通常认为是旋转一周时间的一半。

  • 转速 = 7200 rpm = 7200 / 60 = 120 转/秒。
  • 旋转一周所需时间 = 公式。
  • 平均旋转延迟时间 公式。

③ 数据传输时间 (Data Transfer Time):

  • 这是读取一个扇区的数据所需的时间。
  • 一个磁道有500个扇区,读取一个扇区的时间就是旋转一周时间的 1/500。
  • 传输时间 公式。

总平均访问时间:

  • 公式
  • 公式。

(3)

① DMA总线请求次数计算:

  • 在周期挪用DMA方式下,每当I/O接口的数据缓冲区被填满时,DMA控制器就会向CPU发出一次总线请求,来传送这部分数据。
  • 一个扇区的数据总量 = 512 字节。
  • DMA控制器的数据缓冲区大小 = 64 位 = 64 / 8 = 8 字节。
  • 总线请求次数 = 公式。

结论: 在一个扇区读写过程中,DMA控制器向CPU发送了 64次 总线请求。

② DMA控制器可以获得总线使用权。

  • 原因:这是一个基本的总线仲裁设计原则。DMA方式主要用于高速I/O设备,为了防止因数据来不及传送而造成缓冲区数据被覆盖、最终导致数据丢失的严重问题,DMA的总线请求优先级通常被设计为高于CPU的访存请求。当两者同时需要访问主存时,总线仲裁器会优先将总线使用权授予DMA控制器。这样做虽然会使CPU暂停一个或几个总线周期,但保证了I/O数据传输的完整性和正确性,这对整个系统的可靠性至关重要。