5.2.1 设备独立性软件
设备独立性软件(也称与设备无关的软件)位于设备驱动程序之上,是内核I/O子系统的最高层。该层与设备驱动程序之间的界限并非固定,常因操作系统设计或设备类型而异。例如,某些通常由设备独立性软件实现的功能,有时会被下放至驱动程序中。这种设计差异源于对系统性能、代码复用性及驱动程序效率等多方面因素的综合权衡。总体而言,其核心职责是实现各类设备的公共操作,为上层提供统一、抽象的IO接口。具体包括以下五项公共功能。
提供统一的驱动程序接口。为便于驱动开发与系统扩展,所有设备驱动程序应遵循一致的接口规范。设备独立性软件负责将抽象设备名映射到具体的物理设备,并定位相应驱动程序的入口,同时确保IO操作通过内核受控路径执行,保障系统安全。缓冲管理。系统普遍采用缓冲机制以缓解CPU与外设之间的速度差异,提高CPU利用率。缓冲形式包括单缓冲、双缓冲、环形缓冲和缓冲池等,可根据应用场景灵活选用。差错控制。I/O设备因含机械与电气部件,故障率较高,产生的错误可分为两类:暂时性错误(如网络丢包),通常通过重试纠正,仅当连续失败后才视为持久性错误。此类错误主要由驱动程序处理,设备无关层仅介入驱动程序无法解决的情形。持久性错误(如磁盘划痕),操作系统可将其记录至坏块表,后续I/O自动绕过,避免更换整盘。独占设备的分配与回收。对打印机等独占设备,系统需要统一分配以避免竞争。进程请求设备时,若设备空闲,则立即分配;否则,被阻塞并加入等待队列。设备释放时,若队列非空,则唤醒队首进程;否则,置设备状态为“空闲”,完成回收。提供统一的逻辑数据块。不同设备的数据交换单位各异:字符设备以字节为单位,块设备以固定大小的数据块为单位,并且块长可能不一。设备独立性软件通过抽象层屏蔽这些差异,向上层提供大小统一的逻辑数据块,使上层无须感知底层设备特性。
5.2.2 高速缓存与缓冲区
1. 磁盘高速缓存(Disk Cache)
操作系统采用磁盘高速缓存技术以提高磁盘I/O性能,访问高速缓存中的数据比直接读/写磁盘更高效。磁盘高速缓存不同于通常意义下的位于CPU与主存之间的硬件高速缓存,而是指利用内存中的存储空间暂存从磁盘读取的盘块数据。这些数据在逻辑上是磁盘内容的副本,物理上则驻留在内存中。磁盘高速缓存在内存中有两种组织形式:一种是在内存中开辟固定大小的专用缓存区;另一种是将系统空闲内存作为动态缓冲,供请求分页系统和磁盘I/O子系统共享使用。
2. 缓冲区(Buffer)
在设备管理子系统中,引入缓冲区的主要目的如下:
- 缓和CPU与I/O设备间速度不匹配的矛盾。
- 减少对CPU的中断频率,放宽对中断响应时间的限制。
- 解决基本数据单元大小(数据粒度)不匹配的问题。
- 提高CPU与I/O设备之间的并行性。
缓冲区的实现方法包括:
- 采用硬件缓冲器,但由于成本较高,除一些关键部位外一般不采用。
- 利用内存作为缓冲区,本节要介绍的正是由内存组成的缓冲区。
根据系统设置的缓冲区数量,缓冲技术可分为以下几种:
(1) 单缓冲
当用户进程发出I/O请求时,操作系统在内存中为其分配一个缓冲区,其大小通常为一个数据块。在块设备输入过程中,假设设备将一块数据送入缓冲区的时间为 ,操作系统将缓冲区数据传送到用户工作区的时间为 ,CPU处理该块数据的时间为 。对于块设备,必须等整块数据装入缓冲区后,才能将其传送到工作区。
在单缓冲中,设备向缓冲区写入数据的时间 可与CPU处理前一块数据的时间 并行。当 时,设备向缓冲区填充数据的速度慢于CPU处理数据的速度。此时,CPU在完成当前数据块的处理后,必须等待设备将下一块数据完整写入缓冲区;只有缓冲区装满后,操作系统才能将该数据块从缓冲区传送到用户工作区。处理每块数据所需的时间为 。
当 时,设备填充缓冲区的速度快于CPU的处理速度。此时,缓冲区一旦装满,设备便无法继续写入新数据,必须等待CPU完成对当前工作区数据的处理;此后,操作系统才能将缓冲区中的数据移至工作区,从而释放缓冲区空间。处理每块数据所需的时间为 。
综上,单缓冲处理每块数据所需的时间为 。
由于单缓冲区是共享资源,设备与CPU对其访问必须互斥。若CPU尚未取走缓冲区中的数据,即使设备已准备好新数据,也无法写入缓冲区,此时设备需等待CPU释放缓冲区。
(2) 双缓冲
为了加快输入/输出速度,提高设备利用率,引入了双缓冲机制(也称缓冲对换)。当设备输入数据时,先将数据送入缓冲区1;装满后,转向缓冲区2写入。此时,操作系统可从已满的缓冲区1中取出数据送入用户工作区,并由CPU进行处理。当缓冲区1的数据处理完后,若缓冲区2已装满,则操作系统切换到从缓冲区2中取数据送入用户工作区,而设备又可以开始向缓冲区1写入新数据。可见,双缓冲显著提高了设备与CPU的并行程度。
仍假设设备输入数据到缓冲区、数据传送到工作区和处理的时间分别为 、 和 。在双缓冲中,设备向一个缓冲区写入数据的时间 可与操作系统传送及处理的时间 并行。
当 时,设备输入所需时间大于数据传送与处理的总时间。此时,设备可连续工作。假设在某一时刻,缓冲区1为空,缓冲区2已满:操作系统开始将缓冲区2的数据传送到工作区(耗时 ),CPU随即处理该数据(耗时 ),同时设备向缓冲区1写入新数据。由于 ,当缓冲区2的数据处理完毕时,缓冲区1尚未装满,系统必须等待其装满后,才能将下一块数据从缓冲区1传送到工作区。处理每块数据所需的时间为 。
当 时,设备输入较快,CPU无须等待设备。类似地,当缓冲区1为空、缓冲区2已满时:操作系统传送并处理缓冲区2的数据(共耗时 ),同时设备向缓冲区1写入数据。由于 ,缓冲区1很快装满,但系统仍需等待缓冲区2的数据完全处理完毕,才能切换至缓冲区1并传送其内容。处理每块数据所需的时间为 。
综上,双缓冲处理每块数据的时间为 。
在双机通信场景中,若要实现全双工通信(双方同时收发数据),每台机器需分别设置发送缓冲区和接收缓冲区。A机的发送缓冲区对应B机的接收缓冲区,反之亦然。若仅在每台机器中配置单一缓冲区,则无法同时进行发送与接收操作。
(3) 循环缓冲
在双缓冲机制中,当输入与输出速度基本匹配时,能够取得较好的效果;但若两者速率相差较大,则双缓冲难以充分发挥作用。为此,可引入多缓冲机制,并将多个缓冲区组织成循环缓冲区的形式。循环缓冲由若干个大小相等的缓冲区构成,每个缓冲区包含一个链接指针,指向下一个缓冲区;最后一个缓冲区的指针则指向第一个缓冲区,从而形成一个循环队列结构。
系统需维护两个指针:in 和 out。其中,in 指向下一个待写入的空缓冲区,out 指向下一个待读取的满缓冲区。输入进程和计算进程在运行过程中分别推进 in 和 out 指针,沿链接方向循环移动。采用循环缓冲技术,可以实现输入进程与计算进程的并行执行。由于两者的处理速度可能不一致,在运行过程中可能出现以下两种同步情形。
in追赶上out(称为系统受计算限制)。表明输入进程的写入速度快于计算进程的处理速度,导致所有缓冲区均被填满,无空缓冲区可供继续写入。此时,输入进程必须阻塞,直至计算进程从某个缓冲区中取走数据,释放出一个空缓冲区,并唤醒输入进程。out追赶上in(称为系统受I/O限制)。表明计算进程的处理速度快于输入进程的供给速度,导致所有缓冲区均为空,无数据可供继续处理。此时,计算进程必须阻塞,直至输入进程向某个缓冲区写入数据,使其变为满缓冲区,并唤醒计算进程。
(4) 缓冲池
相比于单个缓冲区(仅是一块内存区域),缓冲池是一种包含管理数据结构和操作函数的软件机制,用于统一管理多个缓冲区,并支持多进程共享使用。
缓冲池由系统统一管理的供多个进程共享的一组缓冲区构成。根据使用状态,这些缓冲区被组织为以下队列:
空缓冲队列,由空缓冲区链接而成;输入队列,由装满输入数据的缓冲区链接而成;输出队列,由装满输出数据的缓冲区链接而成。
在操作过程中,缓冲区可动态扮演以下四种角色:
收容输入缓冲区(hin),用于暂存输入数据;提取输入缓冲区(sin),用于读取输入数据;收容输出缓冲区(hout),用于暂存输出数据;提取输出缓冲区(sout),用于读取输出数据。
缓冲池中的缓冲区按以下4种方式工作。
收容输入。输入进程需要输入数据时,从空缓冲队列队首摘取一个空缓冲区,作为收容输入缓冲区,将输入数据写入其中,装满后将其挂到输入队列队尾。提取输入。计算进程需要输入数据时,从输入队列队首摘取一个缓冲区,作为提取输入缓冲区,从中读取数据,读取完毕后将其挂到空缓冲队列队尾。收容输出。计算进程需要输出数据时,从空缓冲队列队首摘取一个空缓冲区,作为收容输出缓冲区,将输出数据写入其中,装满后将其挂到输出队列队尾。提取输出。输出进程需要输出数据时,从输出队列队首摘取一个缓冲区,作为提取输出缓冲区,从中读取数据,读取完毕后将其挂到空缓冲队列队尾。
对于循环缓冲和缓冲池,本节仅介绍其工作机制,不涉及时间性能的定量分析。而对于单缓冲和双缓冲,只要依据前述模型进行分析,即可求解任意场景下处理每块数据所需的时间。
3. 高速缓存与缓冲区的对比
在I/O系统中,高速缓存(Cache)是一种利用高速存储介质保存慢速设备数据副本的机制,其访问速度远高于直接访问慢速设备。高速缓存与缓冲区的对比如表5.1所示。
表5.1 高速缓存和缓冲区的对比
| 高速缓存 | 缓冲区 | |
|---|---|---|
| 相同点 | 均位于高速设备和低速设备之间,用于缓解二者之间的速度差异 | |
| 区别 | 存放已存在于慢速设备上的数据副本;缓存中的数据可长期驻留,直至被替换 | 存放正在传输过程中的数据;这些数据源自发送方(高速或低速设备),传输完成后通常立即释放 |
| 目的 | 提高重复访问的效率:若所需数据已存在于缓存中,则可避免访问低速设备 | 提高数据传输的效率与并行性:通过暂存数据,协调速度差异、降低中断频率、匹配数据粒度等 |
5.2.3 I/O设备分配与回收
1. 设备分配概述
设备分配是指根据用户的I/O请求分配所需设备的过程。分配的总体原则是:在充分发挥设备使用效率(使设备尽可能忙碌)的同时,避免因分配策略不当引发进程死锁。
2. 设备分配的数据结构
在系统中,可能存在多个通道,一个通道可连接多个控制器,每个控制器又可连接多个物理设备。设备分配的数据结构要能体现出这种从属关系,各数据结构的介绍如下。
-
设备控制表(DCT):系统为每个物理设备配置一张DCT,用于记录该设备的各项属性,如图5.12所示。DCT中的主要字段包括:设备类型:表示设备类型,如打印机、扫描仪、键盘等。设备标识符:即物理设备名,该标识符在系统内是唯一的。设备状态:表示当前设备的状态(忙/闲)。指向控制器表的指针:每个设备由一个控制器控制,该指针指向对应的控制器表。重复执行次数或时间:系统指定I/O操作的可重试次数,超过此值则判定为I/O失败。设备队列的队首指针:指向因请求该设备而阻塞的进程队列(由PCB构成)的队首。
NOTE当某进程释放设备且无其他进程等待时,系统会将DCT中的设备状态置为空闲,完成设备回收。
- 控制器控制表(COCT):每个设备控制器对应一张COCT,用于记录控制器的状态及所辖设备信息,如图5.13(a)所示。通过COCT中的“与控制器连接的通道表指针”,可以找到相应通道的信息。操作系统根据COCT对控制器进行操作和管理。
- 通道控制表(CHCT):每个通道对应一张CHCT,用于管理该通道及其下属控制器,如图5.13(b)所示。通过CHCT中的“与通道连接的控制器表首址”,可以找到该通道管理的所有控制器的信息。操作系统根据CHCT对通道进行操作和管理。
- 系统设备表(SDT):整个系统只维护一张SDT,作为所有物理设备的全局索引。每个表目对应一个设备,通常包含设备类型、标识符等信息。
在多道程序系统中,由于进程数通常多于设备数,必须采用合理的分配策略。主要考虑的因素包括:设备的固有属性、分配算法、分配的安全性以及设备的独立性。
3. 设备分配时应考虑的因素
(1) 设备的固有属性
设备的固有属性可分为三类,需采用不同的分配策略。
独占设备:分配给某进程后,便由其独占使用,直至进程主动释放或终止。共享设备:可同时供多个进程使用,需通过调度机制协调访问顺序(如磁盘)。虚拟设备:通过对独占设备进行虚拟化(如SPOOLing技术),使其在逻辑上表现为可共享设备,允许多个进程并发地提交I/O请求。
(2) 设备分配算法
常用的设备分配算法主要有两种。
FCFS算法。按进程请求设备的先后顺序,排成一个等待队列,优先分配给队首进程。最高优先级优先算法。高优先级进程排在队列前方,优先级相同时按FCFS原则排队。
(3) 设备分配中的安全性
指在分配过程中应避免死锁的发生,主要通过以下两种方式实现。
安全分配方式。每当进程发出I/O请求后,便立即进入阻塞态,直至I/O操作完成才被唤醒。在此期间,进程不再请求任何其他资源,从而有效避免死锁。其优点是安全性高,缺点是CPU与I/O设备串行工作,系统效率较低。不安全分配方式。进程在发出I/O请求后仍继续运行,需要时可发出第二个、第三个I/O请求等。仅当所请求的设备已被其他进程占用时,才进入阻塞态。其优点是单个进程可同时使用多个设备,使进程推进迅速;缺点是可能因循环等待而造成死锁。
4. 设备分配的步骤
下面以独占设备为例,介绍设备分配的过程。
分配设备。首先根据I/O请求中的物理设备名,查找SDT,从中找出该设备的DCT,再根据DCT中的设备状态字段判断其状态。若忙,则将进程PCB挂入设备等待队列;若空闲,则将设备分配给该进程。分配控制器。设备分配后,根据DCT找到对应的COCT,查询控制器的状态。若忙,则将进程PCB挂入控制器等待队列;若空闲,则将控制器分配给该进程。分配通道。控制器分配后,根据COCT找到对应的CHCT,查询通道的状态。若忙,则将进程PCB挂入通道等待队列;若空闲,则将通道分配给该进程。只有当设备、控制器和通道均成功分配后,此次设备分配才算完成,随后可启动设备进行数据传送。
上述过程基于物理设备名发出I/O请求。若指定设备已被其他进程占用,则分配失败,说明该方案缺乏设备独立性。为实现设备独立性,进程应使用逻辑设备名。此时,系统从SDT中依次查找该类设备的DCT:若某设备空闲,则进行后续分配;仅当所有同类设备都忙时,才将进程挂入该类设备的公共等待队列。只要存在一个可用设备,系统便会继续进行后续分配流程。
5. 逻辑设备名到物理设备名的映射
为实现设备独立性,进程应使用逻辑设备名请求某类设备。由于系统只能识别物理设备名,需在系统中配置一张逻辑设备表(Logical Unit Table, LUT),用于建立逻辑设备名到物理设备名的映射。LUT的每个表项包含三项内容:逻辑设备名、物理设备名和驱动程序入口地址。当进程使用某个逻辑设备名请求设备时,系统为其分配一台空闲的物理设备,并在LUT中建立相应表目。此后,该进程的所有I/O请求均通过该表项找到对应的物理设备及其驱动程序。
系统中可采用两种方式设置逻辑设备表。
整个系统仅设置一张LUT。所有进程的设备分配情况都记录在同一张LUT中,这就要求所有用户不能使用相同的逻辑设备名,适用于单用户系统。为每个用户设置一张LUT。系统仍维护全局的系统设备表(SDT)。不同用户可以使用相同的逻辑设备名,互不干扰,适用于多用户系统。
5.2.4 SPOOLing 技术(假脱机技术)
为缓和CPU的高速性与I/O设备低速性之间的矛盾,操作系统引入了 SPOOLing,即假脱机技术。其思想源于早期的脱机I/O方式:依赖专用外围控制机,在主机不参与的情况下完成I/O操作。输入时,外围机将低速输入设备(如纸带机)上的数据预先读入高速磁盘;输出时,CPU先将结果高速写入磁盘,再由外围机将数据送至低速输出设备(如打印机)。由于整个I/O过程脱离主机控制,因此称为脱机。随着多道程序设计技术的发展,操作系统不再需要物理外围机,而通过专门的输入进程与输出进程,在主机直接控制下模拟外围机的功能:输入进程负责将低速输入设备的数据提前读入磁盘上的输入井;输出进程则将用户作业的输出结果暂存于磁盘的输出井,再逐步送往实际输出设备。由此,I/O操作与CPU计算得以并行执行。
这种以磁盘为缓冲、用软件模拟脱机I/O的机制,正是SPOOLing 技术的本质。“脱机”承袭自早期脱机I/O的思想,“假”则体现在以多道程序和磁盘空间替代外围机,进而将一台物理独占设备虚拟为多台逻辑设备,实现设备共享。
(1) 输入井和输出井
在磁盘上开辟的两个专用存储区域。输入井模拟脱机输入的磁盘,用于暂存输入设备的数据。输出井模拟脱机输出的磁盘,用于暂存用户程序的输出数据。每个进程的输入(或输出)数据以文件形式保存(称为井文件),所有文件按顺序链接成输入队列或输出队列。
(2) 输入缓冲区和输出缓冲区
在内存中开辟的两个缓冲区。输入缓冲区暂存由输入设备送来的数据,随后传送到输入井。输出缓冲区暂存从输出井读出的数据,随后传送到输出设备。
(3) 输入进程和输出进程
输入进程模拟脱机输入的外围控制机,负责将输入设备的数据经输入缓冲区传送到输入井。当CPU需要输入数据时,直接从输入井读取。输出进程模拟脱机输出的外围控制机,负责将用户程序的输出数据写入输出井,并在输出设备空闲时,经输出缓冲区将数据传送到输出设备。
(4) 井管理程序
控制作业与磁盘井之间的信息交换。
打印机是典型的独占设备。通过SPOOLing技术,可将其改造为可供多个用户共享的虚拟设备。当多个用户进程发出打印请求时,SPOOLing 系统接受其请求,但并不真正立即将物理打印机分配给它们,而是由输出进程为每个进程完成以下两项操作。
- 在磁盘输出井中为其分配一个空闲盘块,并将待打印数据写入其中。
- 申请一张用户请求打印表,记录用户的打印要求,并将该表挂到假脱机打印队列上。
完成上述操作后,用户进程即认为打印任务已完成,可继续执行后续代码。实际上,真实打印尚未开始,但该过程对用户完全透明。真正的打印由后台的假脱机打印进程负责。当打印机空闲时,该进程检查假脱机打印队列;若队列非空,则取出队首的请求表,根据其中信息将对应的输出数据从输出井读入内存缓冲区,再送至物理打印机进行输出。一个任务完成后,继续处理下一个;若队列为空,则该进程进入等待状态,直至有新的打印请求将其唤醒。由于用户进程仅需将数据写入磁盘即可返回,而物理打印由后台进程按队列顺序依次执行,多个用户便可并发提交打印请求。系统为每个请求在输出井中分配独立的存储区域,使各进程均以为自己独占了一台打印机。由此,一台物理打印机被虚拟为多台逻辑设备,实现了高效且透明的共享。
SPOOLing 系统的特点:
提高了I/O速度,将对低速I/O设备的操作转化为对磁盘输出井中数据的存取,如同脱机输入/输出一样,有效缓和了CPU与低速I/O设备之间速度不匹配的矛盾;将独占设备改造为共享设备,在假脱机打印机系统中,实际上并未将物理设备分配给任何进程;实现了虚拟设备功能,每个进程都认为自己独占了一台设备。
SPOOLing 技术是一种以空间换时间的技术。它通过开辟磁盘空间作为输入井和输出井,牺牲了存储空间,但显著节省了时间。磁盘是一种高速设备,其与内存交换数据的速度远高于打印机等低速设备。若无SPOOLing 技术,CPU向打印机输出数据时,必须等待缓慢的打印操作完成,才能继续后续工作,造成CPU时间的浪费。而在SPOOLing 技术下,CPU可将待打印数据快速写入磁盘输出井(该过程由输出进程控制),随即继续执行其他任务。若打印机正被占用,SPOOLing系统会将该打印请求挂到等待队列上,待打印机空闲时再按序输出。由于向磁盘写入数据的速度远快于直接驱动打印机,整体I/O效率得以提升,CPU与I/O设备实现了并行工作。
5.2.5 设备驱动程序接口
设备驱动程序是I/O系统上层与设备控制器之间的通信桥梁。其主要任务是接收上层软件发来的抽象I/O请求(如read/write),将这些请求转换为设备可识别的具体命令,并发送给设备控制器以启动设备执行相应操作;同时,也将设备控制器返回的状态和中断信息反馈给上层。
为实现上述通信功能,设备驱动程序应具备以下功能:
- 接收上层软件传递的命令和参数,并将抽象的I/O请求转换为与具体设备相关的操作指令。例如,将逻辑盘块号转换为磁盘的盘面号、磁道号和扇区号;
- 检查用户I/O请求的合法性,查询设备当前状态,传递必要参数,并设置其工作方式;
- 发出I/O命令:若设备空闲,则立即启动设备执行操作;若设备正忙,则将请求进程的PCB挂到该设备的等待队列上以待调度;
- 及时响应设备控制器发出的中断请求,并根据中断类型调用相应的中断处理程序进行处理。
相比于普通应用程序和系统程序,设备驱动程序具有以下特点:
- 它在抽象I/O请求与具体设备操作之间实现双向转换,并将设备状态及操作完成情况及时反馈给请求进程;
- 其实现与设备所采用的I/O控制方式(如中断驱动方式、DMA方式)紧密相关;
- 由于直接操作硬件,不同类型的设备必须配备相应的专用驱动程序;
- 部分底层驱动功能可能由设备固件或系统ROM提供;
- 驱动程序应设计为可重入的,以支持多个进程对同一设备的并发调用。
为使各类设备驱动程序具有统一的接口,操作系统要求:
- 所有驱动程序与内核之间遵循相同或相近的接口规范,便于新增和维护;
- 通过设备管理模块将逻辑设备名映射为物理设备名,并定位到对应的驱动程序入口;
- 对设备访问实施权限控制,防止未授权用户非法使用设备。
5.2.6 I/O操作举例
由于统考对I/O的考查日益深入,本节以C语言中的库函数 scanf() 为例,从执行 scanf("%c", &d) 开始,到键盘输入的字符最终存入变量 d,介绍I/O操作的具体执行过程。
在讨论之前,先补充两个概念:内核缓冲区(位于内核空间)和与之对应的用户缓冲区(位于用户空间)。这两个地址空间相互隔离:内核空间存放操作系统代码和数据,供所有进程共享;而用户程序运行在用户空间。由于系统调用在内核态执行,因此必须先将I/O设备的数据复制到内核缓冲区,在系统调用返回前,再将数据从内核缓冲区复制到用户缓冲区。
当程序调用 scanf("%c", &d) 时,试图通过键盘输入为变量 d 赋值。scanf() 会关联一个由C标准库在用户空间管理的缓冲区 buf。scanf() 函数的执行分为两个阶段。
第一阶段的工作是在C标准库中完成的:
- 检查与
scanf()函数关联的用户缓冲区buf。若其中已有数据,则直接读取;若缓冲区为空,则触发系统调用read,从内核缓冲区中读取数据。 - 执行
read系统调用。在执行trap指令前,需要传入三个参数:- fd:文件描述符,标识输入设备(此处为标准输入)。
- buf:用户空间的缓冲区,用于接收从内核复制的数据。
- count:期望读取的最大字节数。
第二阶段的工作是系统调用,在内核中完成。read 系统调用通过一段包含陷阱指令的代码,使CPU从用户态陷入内核态,执行相应的系统调用服务例程。
进入内核态后,系统调用服务例程访问内核缓冲区,并转至真正执行I/O操作的设备驱动层。在中断驱动方式下,系统调用服务例程的执行过程大致如下。
- 设置相应的I/O参数后,发起I/O的进程P进入阻塞态,CPU调度其他进程运行。
- 用户通过键盘输入字符,该字符被送入键盘I/O接口的数据端口。
- 键盘I/O接口向CPU发出中断请求。
- CPU响应中断,执行键盘中断处理程序,读取字符并将其从I/O端口送入内核缓冲区。
- 进程P被唤醒,并加入就绪队列,等待调度。
- 进程P再次获得CPU后,系统调用服务例程将字符从内核缓冲区复制到用户缓冲区。
- 进程P从系统调用返回,随后
scanf()对缓冲区中的字符进行解析,最终将其存入变量d。
值得注意的是,在此过程中,用户输入的字符首先从键盘I/O接口的数据端口送入内核缓冲区,再从内核缓冲区送入用户缓冲区。前者由设备驱动程序完成(因其需直接操作I/O端口),后者由设备无关的I/O软件层完成(因其不依赖具体硬件)。
5.2.7 本节小结
本节开头提出的问题的参考答案如下。
-
当处理机和外部设备的速度差距较大时,有什么办法可以解决问题?
可采用缓冲技术来缓解CPU与外设速度上的矛盾,即在主存中设立一片缓冲区,外设与CPU的输入/输出都经过该缓冲区,从而减少相互等待,提高系统效率。
-
什么是设备的独立性?引入设备的独立性有什么好处?
设备独立性是指应用程序使用逻辑设备名进行I/O操作,而无须指定具体的物理设备。操作系统在运行时将逻辑设备名动态映射到实际可用的物理设备。引入设备独立性的主要优点包括:
- 简化编程,屏蔽底层硬件细节;
- 提高程序可移植性,使同一程序能在不同硬件配置的系统上运行;
- 支持I/O重定向与设备动态绑定,提升系统灵活性和资源利用率。
