输入输出管理 | OS
I/O 管理概述
I/O 管理需要完成以下 4 部分的内容:
状态跟踪
要能实时掌握外设的状态
设备存取
要实现对设备的存取操作
设备分配
在多用户环境下,负责设备的分配和回收
设备控制
包括设备的驱动、完成和故障的中断处理
I/O 设备
基本概念
设备属性
固有属性:决定设备的使用方式。
独立性:用户编程时使用的设备与实际使用的设备无关。可以提高设备分配的灵活性和设备的利用率。
安全性:可以保证设备不会永久被阻塞。
设备编号(绝对号)
将系统中的每台设备按照某种原则统一进行编号,以便区分和识别设备。
I/O 接口
见 CO7。
I/O 端口
见 CO7。
I/O 控制方式
见 CO7。
I/O 软件层次结构

每层都是利用其下层提供的服务,完成输入/输出功能中的某些子功能,并屏蔽这些功能实现的细节,向高层提供服务。
在层次式结构的 I/O 软件中,只要层次间的接口不变,对某一层次中的软件的修改都不会引起其下层或高层代码的变更,仅最底层才涉及硬件的具体特性。
用户层软件
实现与用户交互的接口,通常情况下用户调用在用户层提供的、与 I/O 操作有关的库函数对设备进行操作。也可以直接使用操作系统提供的系统级 I/O 函数或 API 函数提出 I/O 请求,只不过移植性很差,所以很少直接使用。
通常大部分的 I/O 软件都在操作系统内核,但仍有一小部分在用户层,包括与用户程序链接在一起的库函数。
用户层 I/O 软件必须通过一组系统调用来获取操作系统服务。

实际上 C 标准库中提供的函数并没有涵盖所有底层操作系统提供的功能。另外,虽然在很多情况下使用标准 I/O 库函数就能解决问题,特别是对于磁盘和终端设备(键盘、显示器等)的 I/O 操作。但是,在 UNIX/Linux 系统中,有时用标准 I/O 库函数或系统级 I/O 函数对网络设备进行 I/O 操作时会出现一些问题,因此,也可以基于底层的系统级 I/O 函数自行构造高层次 I/O 函数,以提供适合网络 I/O 的读操作和写操作函数。
设备独立性软件
属于系统调用的处理程序,将系统调用参数翻译成设备操作命令(抽象命令)⚠,实现用户与设备驱动器的统一接口、设备命名、设备保护及设备分配与释放等,同时为设备管理和数据传送提供必要的存储空间。
是 I/O 系统的最高层软件(从这层开始属于操作系统内核)。
设备独立性/设备无关性
使应用程序独立于具体使用的物理设备,用户编程时使用的设备与实际使用的设备无关。一个程序应独立于分配给它的某类设备的具体设备,即在用户程序中只指明 I/O 使用的设备类型即可。
为实现设备独立性而引入了逻辑设备和物理设备这两个概念。在应用程序中,使用逻辑设备名来请求使用某类设备;而在系统实际执行时,必须将逻辑设备名映射成物理设备。
为了实现设备独立性,必须再在驱动程序之上设置一层设备独立性软件。
使用逻辑设备名的好处/引入设备独立性的好处
- 增加设备分配的灵活性。
- 易于实现 I/O 重定向。用于 I/O 操作的设备可以更换(重定向)而不必改变应用程序,使程序运行不受具体机器环境的限制。
- 方便用户编程。
- 便于程序移植。
设备独立性软件的主要功能
执行所有设备的公有操作
包括:
① 对设备的分配与回收;
② 将逻辑设备名映射为物理设备名;
③ 对设备进行保护,禁止用户直接访问设备;
④ 缓冲管理;
⑤ 差错控制;
⑥ 提供独立于设备的大小统一的逻辑块,屏蔽设备之间信息交换单位大小和传输速率的差异。
向用户层(或文件层)提供统一接口
无论何种设备,它们向用户所提供的接口应是相同的。
例如,对各种设备的读/写操作,在应用程序中都统一使用 read/write 命令等。
设备独立性软件与其下层的设备驱动程序之间的界限因操作系统和设备的不同而有所差异,比如一些本应由设备独立性软件实现的功能,也可能放在设备驱动程序实现。这样的差异主要是出于对操作系统、设备独立性软件和设备驱动程序运行效率等多方面因素的权衡。
若功能因设备硬件的不同而不同,则只能由设备厂家提供的设备驱动程序实现。
设备驱动程序
与硬件直接相关,负责具体实现系统对设备发出的操作指令,驱动 I/O 设备工作。
通常每类设备配置一个设备驱动程序。
是 I/O 进程与设备控制器之间的通信程序,通常以进程形式存在。
设备驱动程序向上层用户程序提供一组标准接口,设备具体的差别被设备驱动程序所封装,用于接收上层软件发来的抽象 I/O 要求,如 read 和 write 命令,转换为具体要求后,发送给设备控制器,控制 I/O 设备工作。
也将由设备控制器发来的信号传送给上层,从而为 I/O 内核子系统隐藏设备控制器之间的差异。
当一个设备被连接到主机时,驱动程序负责初始化该设备(如将设备控制器中的寄存器初始化)。
厂家会根据设备特性,在驱动程序中实现一种合适的 I/O 控制方式。
设备驱动程序的功能
为了实现上层应用与设备控制器之间的通信,设备驱动程序应具有以下功能:
- 接收由上层软件发来的命令和参数,并将抽象要求转换为与设备相关的具体要求。例如,将抽象要求中的盘块号转换为磁盘的磁道号、盘面号及扇区号。
- 检査用户 I/O 请求的合法性,了解设备的工作状态,传递与设备操作有关的参数,设置设备的工作方式。
- 发出 I/O 命令,若设备空闲,则立即启动它,完成指定的 I/O 操作;若设备忙,则将请求者的 PCB 挂到设备队列上等待。
- 及时响应由设备控制器发来的中断请求,并根据其中断类型,调用相应的中断处理程序进行处理。
设备驱动程序的特点
相比于普通的应用程序和系统程序,设备驱动程序具有以下差异:
- 设备驱动程序将抽象的 I/O 请求转换成具体的 I/O 操作后,传送给设备控制器,并将设备控制器中记录的设备状态和 I/O 操作的完成情况及时地反馈给请求进程。
- 设备驱动程序与设备采用的 I/O 控制方式紧密相关,常用的 I/O 控制方式是中断驱动方式和 DMA 方式。
- 设备驱动程序与硬件密切相关,对于不同类型的设备,应配置不同的设备驱动程序。
- 由于设备驱动程序与硬件紧密相关,目前很多设备驱动程序的基本部分已固化在 ROM 中。
- 设备驱动程序应允许同时多次调用执行。
设备驱动程序的处理过程
- 将抽象要求转化为具体要求;
- 对服务请求进行校验(包括操作合法性和参数合法性);
- 检查设备的状态;
- 传送必要的参数;
- 启动设备。
中断处理程序
主要任务:进行进程上下文切换,对处理中断信号源进行测试,读取设备状态和修改进程状态等。
由于中断处理与硬件紧密相关,对用户而言,应尽量加以屏蔽,因此放在操作系统的底层,系统的其余部分尽可能少地与之发生联系。
I/O 子系统工作的大致过程
用户程序(用户层软件)
首先,CPU 在用户态执行用户进程,当 CPU 执行到系统调用封装函数对应的指令序列中的陷阱指令时,会从用户态陷入到内核态。
系统调用处理程序和系统调用服务例程(设备独立性软件)
转到内核态执行后,CPU 根据陷阱指令执行时 EAX 寄存器中的系统调用号,选择执行一个相应的系统调用服务例程;在系统调用服务例程的执行过程中可能需要调用具体设备的驱动程序。
设备驱动程序
在设备驱动程序执行过程中启动外设工作。
中断处理程序
硬件设备按驱动程序的命令完成相应的功能。外设准备好后发出中断请求,CPU响应中断后,就调出中断服务程序执行,在中断服务程序中控制主机与设备进行具体的数据交换。
下图是 Linux 系统中 write 操作的执行过程示意图。

如图所示,假定用户程序中有一个语句调用了库函数 print()
,在 printf()
函数中又通过一系列的函数调用,最终转到调用 write()
函数。在 write()
函数对应的指令序列中,一定有一条用于系统调用的陷阱指令,在 IA-32 + Linux 系统中就是指令 int $0x80
或 sysenter
。该陷阱指令执行后,进程就从用户态陷入到内核态执行。Linux 中有一个系统调用的统一入口,即系统调用处理程序 system_call()
。CPU 执行陷阱指令后,便转到 system_call()
的第一条指令执行。在 system_call()
中,将根据 EAX 寄存器中的系统调用号跳转到当前系统调用对应的系统调用服务例程 sys_write()
去执行。system_cal()
执行结束时,从内核态返回到用户态下的陷阱指令后面一条指令继续执行。
I/O 子系统各层典型的操作
用户层软件
将二进制整数转换成 ASCII 码格式打印
设备独立性软件
检查用户是否有权使用设备
缓冲区管理
设备驱动程序(涉及操作具体设备)
向设备寄存器写命令
磁盘调度
接收进程发来的 I/O 命令和参数,并检查其合法性
发出 I/O 命令
查询 I/O 设备的状态
计算数据所在磁盘的柱面号、磁头号、扇区号
应用程序 I/O 接口
在 I/O 系统与高层间的接口中,根据设备类型的不同,又进一步分为若干接口。
操作系统将所有设备划分成字符设备和块设备两类(不考虑面向网络),主要是为了便于操作系统对各种不同字符设备和不同块设备的共同特点进行抽象,从而在实现操作系统中的 I/O 软件时,可以尽可能多地划分出与设备无关的软件部分。例如,对于块设备,可以在文件系统只处理与设备无关的抽象块设备,而把与设备相关的部分放到更低层次的设备驱动程序中实现。
字符设备接口
数据的存取和传输以字符为单位的设备,如键盘、打印机等。
传输效率较低、不可寻址。
输入/输出时通常采用中断驱动方式。
get 和 put 操作:由于字符设备不可寻址,只能采取顺序存取方式,通常为字符设备建立一个字符缓冲区,用户程序通过 get 操作从缓冲区获取字符,通过 put 操作将字符输出到缓冲区。
in-control 指令:字符设备种类繁多,差异甚大,因此在接口中提供一种通用的 in-control 指令来处理它们(包含了许多参数,每个参数表示一个与具体设备相关的特定功能)。
字符设备都属于独占设备,因此接口中还需提供打开和关闭操作,以实现互斥共享。
块设备接口
数据的存取和传输以数据块为单位的设备,典型的块设备是磁盘。
传输速率较高、可寻址。
磁盘设备的 I/O 常采用 DMA 方式。
隐藏了磁盘的二维结构。在二维结构中,每个扇区的地址需要用磁道号和扇区号来表示。块设备接口将磁盘的所有扇区从 0 到 $n-1$ 依次编号,这样就将二维结构变为一种线性序列。
将抽象命令映射为低层操作。块设备接口支持上层发来的对文件或设备的打开、读、写和关闭等抽象命令,该接口将上述命令映射为设备能识别的较低层的具体操作。
内存映射接口通过内存的字节数组来访问磁盘,而不提供读/写磁盘操作。映射文件到内存的系统调用返回包含文件副本的一个虚拟内存地址。只在需要访问内存映像时,才由虚拟存储器实际调页。内存映射文件的访问如同内存读/写一样简单,极大地方便了程序员。
网络设备接口
现代操作系统都提供面向网络的功能,因此还需要提供相应的网络软件和网络通信接口,使计算机能够通过网络与网络上的其他计算机进行通信或上网浏览。
许多操作系统提供的网络 I/O 接口为网络套接字接口,套接字接口的系统调用使应用程序创建的本地套接字连接到远程应用程序创建的套接字,通过此连接发送和接收数据。
阻塞 I/O 和非阻塞 I/O 接口
操作系统的 I/O 接口还涉及两种模式:阻塞和非阻塞。
阻塞 I/O
当用户进程调用 I/O 操作时,进程就被阻塞,并移到阻塞队列,I/O 操作完成,进程才被唤醒,移到就绪队列。
当进程恢复执行时,它收到系统调用的返回值,并继续处理数据。
大多数操作系统提供的 I/O 接口都是采用阻塞 I/O。
优点:操作简单,实现难度低,适合并发量小的应用开发。
缺点:I/O 执行阶段进程会一直阻塞下去。
非阻塞 I/O
指当用户进程调用 I/O 操作时,不阻塞该进程,但进程需要不断询问 I/O 操作是否完成,在 I/O 执行阶段,进程还可以做其他事情。当问到 I/O 操作完成后,系统将数据从内核复制到用户空间,进程继续处理数据。
这里说的 “内核” 即内核缓冲区,“用户空间” 是指用户缓冲区。
优点:进程在等待 I/O 期间不会阻塞,可以做其他事情,适合并发量大的应用开发。
缺点:轮询方式询问 I/O 结果,会占用 CPU 的时间。
设备独立性软件
也称与设备无关的软件,是 I/O 系统的最高层软件。
设备独立性软件的下层是设备驱动程序,其界限因操作系统和设备的不同而有所差异。比如,一些本应由设备独立性软件实现的功能,也可能放在设备驱动程序中实现。这样的差异主要是出于对操作系统、设备独立性软件和设备驱动程序运行效率等多方面因素的权衡。
总体而言,设备独立性软件包括执行所有设备公有操作的软件。
磁盘高速缓存 Disk Cache
操作系统中使用磁盘高速缓存技术来提高磁盘的 I/O 速度,对访问高速缓存要比访问原始磁盘数据更为高效。
不同于通常意义下的介于 CPU 与内存之间的小容量高速存储器,磁盘高速缓存技术是指利用内存中的存储空间来暂存从磁盘中读出的一系列盘块中的信息。因此,磁盘高速缓存逻辑上属于磁盘,物理上则是驻留在内存中的盘块⚠,所以也叫高速缓存 RAM。
访问磁盘高速缓存比访问磁盘原始数据更高效、速度更快,减少了磁盘 I/O 次数,进而改善 CPU 与 I/O 设备速度不匹配的问题。
高速缓存在内存中分为两种形式:
- 内存中开辟一个单独的存储空间作为磁盘高速缓存,大小固定。
- 把未利用的内存空间作为一个缓冲池,供请求分页系统和磁盘 I/O 时共享。
⚠磁盘高速缓存位于内核空间。
缓冲区 Buffer
引入目的
- 缓和 CPU 与 I/O 设备间速度不匹配的矛盾。
- 降低对 CPU 的中断频率,放宽对 CPU 中断响应时间的限制。
- 解决基本数据单元大小(即数据粒度)不匹配的问题。
- 提高 CPU 和 I/O 设备之间的并行性。
在系统内存中设置磁盘缓冲区的主要目的是减少磁盘 I/O 次数。
例如,假设一个文件有 10 个物理块。若没有设置磁盘缓冲区,则每次 I/O 只能将 1 块的内容读入内存,读整个文件总共需要 10 次 I/O。若设置了磁盘缓冲区,缓冲区可存储 10 个物理块的内容,则可以通过一次 I/O 就将文件对应的 10 个物理块全部读入缓冲区,之后便无需再启动磁盘 I/O。
实现方法
采用硬件缓冲器
成本太高,除一些关键部位外,一般不采用。
利用内存作为缓冲区
本节要介绍的正是由内存组成的缓冲区。
内存缓冲区的具体实现
用户进程在提出 I/O 请求时,指定的用来存放 I/O 数据的缓冲区在用户空间中。例如,文件读函数 fread(buf, size, num, fp)
中的缓冲区 buf
在用户空间中。通过陷阱指令陷人到内核态后,内核通常会在内核空间中再开辟一个或两个缓冲区,这样,在底层 I/O 软件控制设备进行 I/O 操作时,就直接使用内核空间中的缓冲区来存放 I/O 数据。
为何不直接使用用户空间缓冲区呢?因为,如果直接使用用户空间缓冲区,那么,在外设进行 I/O 期间,由于用户进程被阻塞而使用户空间的缓冲区所在页面可能被替换出去,这样就无法获得缓冲区中的 I/O 数据。其他原因包括:可解决不同块设备读写单位的不一致、便于共享等。
每个设备的 I/O 都需要使用缓冲区,因而缓冲区的申请和管理等处理是所有设备公共的,可以包含在与设备无关的 I/O 软件部分。
用户缓冲区是指当用户进程读文件时,通常先申请一块内存数组,称为 Buffer,用来存放读取的数据。每次 read 调用,将读取的数据写入 Buffer,之后程序都从 Buffer 中获取数据,当 Buffer 使用完后,再进行下一次调用,填充 Buffer。可见,用户缓冲区的目的是减少系统调用次数,从而降低系统在用户态与核心态之间切换的开销。
当用户进程从磁盘读取数据时,不直接读磁盘,而将内核缓冲区中的数据复制到用户缓冲区中。若内核缓冲区中没有数据,则内核请求从磁盘读取,然后将进程挂起,为其他进程服务,等到数据已读取到内核缓冲区中时,将内核缓冲区中的数据复制到用户进程的缓冲区,才通知进程(当然,I/O 模型不同,处理的方式也不同)。当用户进程需要写数据时,数据可能不直接写入磁盘,而将数据写入内核缓冲区,时机适当时(如内核缓冲区的数据积累到一定量后),内核才将内核缓冲区的数据写入磁盘。可见,内核缓冲区是为了在操作系统级别提高磁盘 I/O 效率,优化磁盘写操作。
可以认为,read 是把数据从内核缓冲区复制到进程缓冲区,write 是把进程缓冲区复制到内核缓冲区。write 不一定会写盘,可能会等内核缓冲区的数据累计到一定量时,再一次写盘。
缓冲区读写特点
- 缓冲区非空时不能往缓冲区中冲入数据。
- 缓冲区满了之后才能把其中的数据传出。
缓冲技术分类
单缓冲、双缓冲、循环缓冲、缓冲池。
单缓冲
每当用户进程发出一个 I/O 请求,操作系统便在内存中为之分配一个缓冲区。通常,一个缓冲区的大小就是一个块。
在块设备输入时,假定从设备将一块数据输入到缓冲区的时间为 T,操作系统将该缓冲区中的数据传送到工作区的时间为 M,而 CPU 对这一块数据进行处理的时间为 C。如无明确说明,通常认为缓冲区的大小和工作区的大小相等。

特点:C 与 T 可并行。
处理 $n$ 块数据总用时:$n$ × (max(T, C) + M) + C
当 T > C 时,CPU 处理一块完数据后,暂时不能将下一块数据传送到工作区,必须等待缓冲区装满数据,再将下一块数据从缓冲区传送到工作区,平均处理一块数据的时间为 T + M。
当 T < C 时,缓冲区中装满数据后,暂时不能继续送入下一块数据,必须等待 CPU 处理完上一块数据,再将下一块数据从缓冲区传送到工作区,平均处理一块数据的时间为 C + M。
处理一块数据近似平均用时($n$ 较大时):max(T, C) + M
双缓冲
由于缓冲区是共享资源,生产者与消费者在使用缓冲区时必须互斥。如果消费者尚未取走缓冲区中的数据,即使生产者又生产出新的数据,也无法将它送入缓冲区,生产者等待。如果为生产者与消费者设置了两个缓冲区,便能解决这一问题。
为了加快输入和输出速度,提高设备利用率,引入了双缓冲机制,也称缓冲对换。
如下图所示,当设备输入数据时,先将数据送入缓冲区 1,装满后便转向缓冲区 2。此时,操作系统可以从缓冲区 1 中取出数据,送入用户进程,并由 CPU 对数据进行处理。当缓冲区 1 中取出的数据处理完后,若缓冲区 2 已冲满,则操作系统又从缓冲区 2 中取出数据送入用户进程处理,而设备又可以开始将数据送入缓冲区 1。可见,双缓冲机制提高了设备和 CPU 的并行程度。

特点:C 和 M 可以与 T 并行。
- 处理 $n$ 块数据总用时:$n$ × max(M+C, T) + M + C
- 处理一块数据近似平均用时($n$ 较大时):max(M+C, T)
若 M + C < T,则可使块设备连续输入;若 M + C > T,则可使 CPU 不必等待设备输入。
对于字符设备,若采用行输入方式,则采用双缓冲通常能消除用户的等待时间,即用户在输入完第一行后,在 CPU 执行第一行中的命令时,用户可继续向第二缓冲区输入下一行数据。
💦双机通信时缓冲区的设置

若两台机器之间仅配置了单缓冲,如图 a 所示,则它们在任意时刻都只能实现单方向的数据传输,而绝不允许双方同时向对方发送数据。为了实现双向数据传输,必须在两台机器中都设置两个缓冲区,一个用作发送缓冲区,另一个用作接收缓冲区,如图 b 所示。
循环缓冲
在双缓冲机制中,当输入与输出的速度基本匹配时,能取得较好的效果。但若两者的速度相差甚远,则双缓冲区的效果不会太理想。为此,又引入了多缓冲机制,让多个缓冲区组成循环缓冲区的形式,如下图所示,灰色表示已装满数据的缓冲区,白色表示空缓冲区。

显然,循环缓冲的数据结构为循环队列。可设置两个指针,分别指向第一个空缓冲区和第一个满缓冲区。
缓冲池
上述的缓冲区是专门为特定的生产者和消费者设置的,它们属于专用缓冲。当系统较大时,应该有许多这样的循环缓冲,这不仅要消耗大量的内存空间,而且其利用率不高。为了提高缓冲区的利用率,目前广泛流行既可用于输入又可用于输出的公用缓冲池,在池中设置了多个可供若干个进程共享的缓冲区。
相比于缓冲区(仅是一块内存空间),缓冲池是包含一个用于管理自身的数据结构和一组操作函数的管理机制,用于管理多个缓冲区。缓冲池可供多个进程共享使用。
缓冲池的组成
缓冲池管理着多个缓冲区,每个缓冲区由用于标识和管理的缓冲首部以及用于存放数据的缓冲体两部分组成。缓冲首部一般包括缓冲区号、设备号、设备上的数据块号、同步信号量以及队列链接指针等。
为了管理上的方便,一般将缓冲池中具有相同类型的缓冲区链接成一个队列,于是可形成以下三个队列(按使用状况):
- 空缓冲队列
- 装满输入数据的缓冲队列(输入队列)
- 装满输出数据的缓冲队列(输出队列)
按操作性质/状态,也可分为四种工作缓冲区:
- 用于收容输入数据的工作缓冲区(从空缓冲队列取得准备装入输入数据的缓冲区)
- 用于提取输入数据的工作缓冲区(从输入队列取得准备提取输入数据的缓冲区)
- 用于收容输出数据的工作缓冲区(从空缓冲队列取得准备装入输出数据的缓冲区)
- 用于提取输出数据的工作缓冲区(从输出队列取得准备提取输出数据的缓冲区)
缓冲区的工作方式
缓冲池中的缓冲区有如下 4 种工作方式:

- 收容输入:输入进程需要输入数据时,从空缓冲队列的队首摘下一个空缓冲区,作为收容输入工作缓冲区,然后将数据输入其中,装满后再将它挂到输入队列的队尾。
- 提取输入:计算进程需要输入数据时,从输入队列的队首取得一个缓冲区,作为提取输入工作缓冲区,从中提取数据,用完该数据后将它挂到空缓冲队列的列尾。
- 收容输出:计算进程需要输出数据时,从空缓冲队列的队首取得一个空缓冲区,作为收容输出工作缓冲区,当其中装满数据后,再将它挂到输出队列的队尾。
- 提取输出:输出进程需要输出数据时,从输出队列的队首取得一个装满输出数据的缓冲区,作为提取输出工作缓冲区,当数据提取完后,再将它挂到空缓冲队列的队尾。
缓冲区属于临界资源,同步与互斥要着重考虑。
高速缓存 vs 缓冲区

高速缓存位于内核空间,而缓冲区则是用户缓冲区和内核缓冲区一起使用。
设备分配与回收
设备分配概述
设备分配是指根据用户的 I/O 请求分配所需的设备。
分配总原则
充分发挥设备的使用特性,尽可能让设备忙碌,又要避免由于不合理的分配方法造成进程死锁。
设备分类(按使用方式)
独占设备
同一时刻只能由一个进程占用的设备。
在一个用户作业未完成或退出之前,此设备不能分配给其他作业。
所有字符设备都是独占设备⚠,如输入机、磁带机、打印机等。
共享设备
一段时间内允许多个进程同时访问的设备(分时式共享),如磁盘。
共享设备必须是可寻址和可随机访问的设备⚠。
虚拟设备
通过软件技术将独占设备改造成共享设备,以提高系统资源/独占设备的利用率。
例如,通过 SPOOLing 技术将一台打印机虚拟成多台打印机。
虚拟设备并不允许用户使用更多的物理设备,也与用户使用物理设备的标准化方式无关。
这种技术实质上就是实现了对设备的 I/O 操作的批处理。
设备分配的数据结构
在系统中,可能存在多个通道,每个通道可以连接多个控制器,每个控制器可以连接多个物理设备。设备分配的数据结构要能体现出这种从属关系。

设备控制表 DCT
一张 DCT 表征一个设备,其表项是设备的各个属性。

在 DCT 中,应该有下列字段:
设备类型:表示设备类型,如打印机、扫描仪、键盘等。
设备标识符:即物理设备名,每个设备在系统中的物理设备名是唯一的。
设备状态:表示当前设备的状态(忙/闲)。
指向控制器表的指针:每个设备由一个控制器控制,该指针指向对应的控制器表。
重复执行次数或时间:重复执行次数达到规定值仍不成功时,才认为此次 I/O 失败。
设备队列的队首指针:指向正在等待该设备的进程队列(由进程 PCB 组成)的队首。
下面 COCT 中的控制器队列和 CHCT 中的通道队列均为正在等待该控制器/通道的进程(PCB)阻塞队列。
控制器控制表 COCT
每个控制器设置一张 COCT。

操作系统根据 COCT 的信息对控制器进行操作和管理。每个控制器由一个通道控制,通过表项 “与控制器连接的通道表指针” 可以找到相应通道的信息。
通道控制表 CHCT
每个通道设置一张 CHCT。

操作系统根据 CHCT 的信息对通道进行操作和管理。一个通道可为多个控制器服务,通过表项 “与通道连接的控制器表首址” 可以找到该通道管理的所有控制器的信息。
系统设备表 SDT
整个系统只有一张 SDT,记录已连接到系统中的所有物理设备的情况,每个物理设备对应一个表目。

设备分配的策略
分配原则
应根据设备特性、用户要求和系统配置情况,既要充分发挥设备的使用效率,又要避免造成进程死锁,还要将用户程序和具体设备隔离开。
考虑因素
I/O 设备的固有属性
1)独占设备
将它分配给某个进程后,便由该进程独占,直至进程完成或释放该设备。
为了避免诸进程对独占设备的争夺,必须由系统来统一分配,不允许进程自行使用。每当进程需要使用某(独占)设备时,必须先提出申请。
2)共享设备
可将它同时分配给多个进程,需要合理调度各个进程访问该设备的先后次序。
3)虚拟设备
属于可共享设备,可将它同时分配给多个进程使用。
设备分配算法
针对设备分配,通常只采用以下两种分配算法:
1)FCFS 算法。
2)最高优先级优先算法。对于优先级相同的 I/O 请求,则按 FCFS 原则排队。
I/O 设备分配的安全性(设备分配中防止进程发生死锁)
1)安全分配方式
每当进程发出 I/O 请求后,便进入阻塞态,直到其 I/O 操作完成时才被唤醒。
这样,进程一旦获得某种设备后便会阻塞,不能再请求任何资源,而在它阻塞时也不保持任何资源⚠,破坏了 ”请求和保持“ 这一死锁必要条件。
其优点是设备分配安全,缺点是 CPU 和 I/O 设备是串行工作的(对同一进程而言)。
2)不安全分配方式
进程在发出 I/O 请求后仍继续运行,需要时又会发出第二个、第三个 I/O 请求等。仅当进程所请求的设备已被另一进程占用时,才进入阻塞态。
优点是一个进程可同时操作多个设备,使进程推进迅速;缺点是有可能造成死锁。
因此在设备分配程序中,应对本次的设备分配是否会发生死锁进行安全性计算,仅当计算结果说明分配是安全的情况下,才进行设备分配。
静态分配和动态分配
1)静态分配
用户作业执行开始前一次性分配完该进程所要求的全部设备、控制器等,一旦分配就一直为该作业占用,直到该作业完成或被撤销(破坏 ”请求和保持“ )。
主要用于独占设备的分配。
不会出现死锁,但设备使用效率低,不符合分配总原则。
2)动态分配
在进程执行过程中根据需要进行分配,用完即释放。
有利于提高设备利用率。
若分配算法使用不当则可能造成死锁
对独占设备既可采用静态分配,又可采用动态分配,但往往采用静态分配;
对共享设备一般采用动态分配,但在每个 I/O 传输的单位时间内只被一个进程所占有。
逻辑设备名到物理设备名的映射
为了实现设备的独立性,进程中应使用逻辑设备名来请求某类设备。但是,系统只识别物理设备名,因此在系统中需要配置一张逻辑设备表,用于将逻辑设备名映射为物理设备名。
逻辑设备表 LUT (Logical Unit Table)
用于将逻辑设备名映射为物理设备名。
LUT 的每个表项包含 3 项内容:逻辑设备名、物理设备名、设备驱动程序入口地址。

当进程用逻辑设备名来请求分配设备时,操作系统根据用户进程指定的设备类型(逻辑设备名)查找系统设备表,找到指定类型并且空闲的设备分配给进程,并在 LUT 中建立一个表目,填上应用程序中使用的逻辑设备名和系统分配的物理设备名,以及该设备驱动程序的入口地址。之后进程再通过该逻辑设备名请求 I/O 操作时,系统通过查找 LUT 便可找到相应的物理设备和驱动程序。
用户编程时提供的逻辑设备名某种程度上等价于 “设备类型”。
逻辑设备表的设置问题
在系统中可采取两种方式设置逻辑设备表:
整个系统只设置一张 LUT
所有进程的设备分配情况都记录在同一张 LUT 中。
这就要求所有用户不能使用相同的逻辑设备名,主要适用于单用户系统。
为每个用户设置一张 LUT
当用户登录时,系统为该用户建立一个进程,同时也为之建立一张 LUT,并把该表放入该进程的 PCB。
由于通常在多用户系统中都配置了系统设备表,故此时的逻辑设备表可以采用下图中的格式。
设备的分配过程
下面以独占⚠设备为例,介绍设备分配的过程。
分配设备
I/O 请求中的逻辑设备名 → LUT → 物理设备名 → SDT → DCT,根据 DCT 设备状态字段可知设备是否正忙。若忙,则从 SDT 查找第二个该类设备的 DCT,仅当所有该类设备都忙时,才把进程挂在该类设备(第一个?所有?)的等待队列上。而只要有一个该类设备可用,系统便进一步计算分配该设备的安全性。如安全,便可把设备分配给它,并更新 LUT。
分配控制器
设备分配后,DCT → COCT,根据 COCT 中的状态字段可知该控制器是否正忙。若忙,则将进程的 PCB 挂到该控制器等待队列上;若不忙,则将该控制器分配给进程。
分配通道
控制器分配后,COCT → CHCT,根据 CHCT 内的状态信息可知该通道是否正忙。若忙,则将进程的 PCB 挂到该通道的等待队列上;若不忙,则将该通道分配给进程。
整个设备分配过程中先后访问的数据结构为 LUT → SDT → DCT → COCT → CHCT。只有在 设备可用 + 控制器可用 + 通道可用 达成的情况下,才能成功分配一个设备,之后便可启动该设备进行数据传送。
为防止 I/O 系统的 “瓶颈” 现象,通常采用多通路的 I/O 系统结构,此时对控制器和通道的分配类似对设备的分配,同样要经过几次反复,仅当所有控制器、通道都忙时,分配才算失败。
设备的回收
进程释放某设备时,将该设备队列中的第一个进程唤醒,该进程得到设备后继续运行。
TODO:汤书中也没有对设备回收的详细讲解。
SPOOLing 技术
问题的提出
慢速独占设备,采用静态分配方式是不利于提高系统效率的。
- 占有这些设备的作业不能有效充分地利用它们,在作业执行期间,这些设备大部分时间处于空闲状态。而且在这些设备分配给一个作业以后,其他作业将无法申请。
- 慢速设备联机传输大大延长了作业的执行时间(和 CPU 串行工作)。例如某进程要向打印机输出要打印的数据,该进程需要等到打印机将数据打印完后才继续执行后续工作。
脱机输入/输出技术
早期操作脱机外围设备是使用两台外围计算机,其中一台外围计算机以最大速度从慢速设备上读取信息并记录到输入磁盘上。然后把包含有输入信息的磁盘人工移动到主处理机上。在多道程序环境下,可让作业从磁盘上读取各自的数据。运行的结果信息写入到输出磁盘上,最后把输出磁盘移动到另一台外围计算机上,该外围计算机会以最大速度读出信息并从打印机上输出。
外围计算机不进行计算,只实现把信息从一台外围设备传送到另一台外围设备上。这种操作独立于主机处理,而不在主处理机的直接控制下进行,所以称作脱机外围设备操作。
😀磁盘是一种高速设备,在与内存交换数据的速度上优于打印机、键盘、鼠标等中低速设备,另外脱机外围设备把独占使用的设备转化为可共享的设备,这样在一定程度上提高了效率。
😟但也带来了若干新的问题:
- 增加了外围计算机,不能充分发挥这些计算机的功效。
- 增加了操作员的手工操作,在主处理机和外围处理机之间要来回装上和取下输入输出卷,这种手工操作出错机会多,效率低。
- 不易实现优先级调度,不同批次中的作业无法搭配运行。
假脱机技术——SPOOLing
引入多道程序技术后,系统便可利用程序来模拟脱机输入/输出时的外围控制机,处理器在运行主进程的同时也可进行联机外围设备操作,这样就能使用一台计算机来完成上述三台计算机实现的功能,以联机的方式得到脱机的效果,将一台独占设备改造成共享设备(“假脱机真联机”)。
SPOOLing 系统的组成
输入井和输出井
在磁盘上开辟的两个存储区域。
输入井模拟脱机输入时的磁盘,用于收容 I/O 设备输入的数据;输出井模拟脱机输出时的磁盘,用于收容用户程序输出的数据。
一个进程的输入(输出)数据保存为一个文件,所有进程的数据输入(输出)文件链接成一个输入(输出)队列。
输入缓冲区和输出缓冲区
在内存中开辟的两个缓冲区,用来暂存数据。
输入缓冲区用于暂存由输入设备送来的数据,以后再传送到输入井;
输出缓冲区用于暂存从输出井送来的数据,以后再传送到输出设备。
输入进程和输出进程(预输入程序和缓输出程序)
模拟脱机 I/O 时的外围计算机。
⚠输入进程将输入数据从输入设备 → 输入缓冲区 → 输入井。当 CPU 需要输入数据时,井管理程序直接从输入井将输入数据读入内存。
⚠井管理程序先将输出数据从内存 → 输出井。待输出设备空闲时,输出进程再将输出数据从输出井 → 输出缓冲区 → 输出设备。
注意预输入程序、缓输出程序、井管理程序各自负责的部分。
井管理程序用于控制作业和磁盘井之间信息的交换;预输入程序、缓输出程序则是模拟外围计算机,控制设备和磁盘井之间信息的交换。
示例:共享打印机
打印机当用户进程请求打印输出时,SPOOLing 系统同意打印,但是并不真正立即把打印机立即分配该进程,而由假脱机管理进程完成两项任务:
- 在磁盘缓冲区为之申请一个空闲盘块,并将要打印的数据送入其中暂存。
- 为用户进程申请一张空白的用户请求打印表,并将用户的打印要求填入其中,再将该表挂到假脱机文件队列上。
对每个用户进程而言,系统并非即时执行真实的打印操作,而只是即时将数据输出到缓冲区。这时的数据并未被真正打印,而只让用户感觉系统已为它打印,真正的打印操作是在打印机空闲且该打印任务在等待队列中已排到队首时进行的。以上过程用户是不可见的。虽然系统中只有一台打印机,但是当进程提出打印请求时,系统都在输出井中为其分配一个缓冲区(相当于分配一台逻辑设备),使每个进程都觉得自己正在独占一台打印机,从而实现对打印机的共享。
SPOOLing 系统的特点
- 提高了 I/O 的速度,将对低速 I/O 设备执行的 I/O 操作演变为对相对高速的磁盘缓冲区中数据的存取,如同脱机输入/输出一样,缓和了 CPU 和低速 I/O 设备之间的速度不匹配的矛盾;
- 将独占设备改造为共享设备,在假脱机打印机系统中,实际上并没有为任何进程分配设备。
- 实现了虚拟设备功能,对每个进程而言,它们都认为自己独占了一个设备。
构成 SPOOLing 系统的基本条件
- 大容量、高速度的外存(作为输入井和输出井)
- SPOOLing 软件(预输入程序、井管理程序、缓输出程序)
SPOOLing 技术实现的前提条件:多道程序设计技术的支持。预输入程序和缓输出程序要与执行 I/O 操作的进程并发执行。
SPOOLing 技术的本质
用软件的方式实现了数据的预输入和缓输出,模拟了脱机的效果。
以空间换时间。在输入和输出之间增加了输入井和输出井的排队转储环节,以消除用户的联机等待时间。用户进程实际分配到的是外存区(即虚拟设备)。
SPOOLing 技术的优势
提高独占设备的利用率(主要目的)。SPOOLing 技术将一台物理设备虚拟为多台逻辑设备,以减少设备的闲置时间,提高设备的吞吐量。
有效减少了进程等待读入/读出信息的时间,加快了作业执行的速度。
假脱机 vs 缓冲
- 假脱机使一个作业的输入/输出与另一作业的执行重叠,而缓冲是将一个作业的输入/输出与该作业的执行重叠。
- 假脱机比缓冲效率更高,因为假脱机可以一次重叠处理两个作业。
- 缓冲使用内存中的有限区域,而假脱机使用磁盘作为巨大的缓冲区。
设备驱动程序接口
为了使所有的设备驱动程序有着统一的接口,
- 一方面要求每个设备驱动程序与操作系统(设备独立性软件)之间都有着相同或相近的接口,这样会使得添加一个新设备驱动程序变得容易,同时也便于开发人员编制设备驱动程序。
- 另一方面,要将抽象的设备名映射到适当的驱动程序上,或者说,将抽象的设备名转换为具体的物理设备名,并进一步可以找到相应物理设备的驱动程序入口。
- 此外,还应对设备进行保护,禁止用户直接访问设备,以防止无权访问的用户使用。
为了简化对外设的处理,在内核高层 I/O 软件中,将所有外设都抽象成一个文件,设备名和文件名在形式上没有任何差别,因而被称为设备文件名。设备作为一种特殊的文件,因此针对文件的常规保护规则也适用于 I/O 设备,系统管理员可为每个设备设置适当的访问权限。
内核中与设备无关的 I/O 软件必须将不同的设备名和文件名映射到对应的设备驱动程序。例如,在UNIX/Linux系统中,一个设备名(如 /dev/disk0)就唯一确定了一个特殊文件的 inode。特殊设备文件对应的 inode 节点中包含主设备号和次设备号,主设备号确定设备类型(如 USB 设备、硬盘设备),因而它被系统用来确定设备驱动程序,次设备号可作为参数传递给设备驱动程序,用以确定进行 I/O 操作的具体设备。
对于每种设备类型,操作系统都要定义一组驱动程序必须支持的函数(例如磁盘驱动程序必须支持读、写、格式化等函数)。驱动程序中通常包含一张表格,这张表格具有针对这些函数指向驱动程序自身的指针。装载驱动程序时,操作系统记录这个函数指针表的地址,所以操作系统需要调用一个函数时,它可以通过这张表格发出间接调用。
设备独立性软件与设备驱动程序之间的关系,和 VFS 与文件系统之间的关系很像。这也是 “设备是特殊的文件” 的体现。
磁盘和固态硬盘
磁盘
见 CO3。
磁盘的管理
磁盘初始化
一个新的磁盘只是一个磁性记录材料的空白盘。在磁盘可以存储数据之前,必须将它分成扇区,以便磁盘控制器能够进行读/写操作,这个过程称为低级格式化(或称物理格式化)。
低级格式化为每个扇区采用特殊的数据结构,填充磁盘。
每个扇区的数据结构通常由头部、数据区域(通常大小为 512B)和尾部组成。头部和尾部包含了一些磁盘控制器所使用的信息,其中利用磁道号、磁头号、扇区号来标志一个扇区,利用 CRC 字段对扇区进行校验。
大多数磁盘在工厂时作为制造过程的一部分就已低级格式化,这种格式化能够让制造商测试磁盘,并且初始化逻辑块号到无损磁盘扇区的映射。
对于许多磁盘,当磁盘控制器低级格式化时,还能指定在头部和尾部之间留下多长的数据区,通常选择 256 或 512 字节等。
分区与逻辑格式化
在可以使用磁盘存储文件之前,操作系统还需要将自己的(文件系统)数据结构记录到磁盘上,分为两步:
将磁盘分为由一个或多个柱面组成的分区(即我们熟悉的 C 盘、D 盘等形式的分区)
创建硬盘分区表:每个分区的起始扇区和大小都记录在磁盘主引导记录的分区表中。
可以将分区作为低级格式化和高级格式化的界限。比如,硬盘的操作系统引导扇区是产生在对硬盘进行高级格式化时,因为操作系统的引导扇区位于磁盘活动分区的引导扇区,因此必然产生在分区之后,也就是高级格式化。
对物理分区进行逻辑格式化(也称高级格式化),即创建文件系统
操作系统将初始的文件系统数据结构存储到分区上(需要清除原磁盘或磁盘分区中所有文件),这些数据结构包括空闲空间和已分配的空间,以及一个初始为空的目录,同时在主引导记录的分区表中标记该分区所使用的文件系统。
即:① 建立文件系统的根目录;② 对保存空闲磁盘块信息的数据结构进行初始化。
引导块
又叫启动块、分区引导记录 PBR,win 系统又称之为分区引导扇区。
包含引导程序(启动管理器),负责启动该分区中的操作系统。
每个分区都从一个引导块开始,即使它现在不包含有一个可启动的操作系统。
分区剩余部分的布局随文件系统的不同而变化。
分区可以是原始的,可以没有文件系统。当没有合适的文件系统时,可以使用原始磁盘。
坏块
由于磁盘有移动部件且容错能力弱,因此容易导致扇区损坏。部分磁盘设置在出厂时就有坏块。
属于硬件故障,操作系统无法修复。
对坏块的处理就是使用某种机制使系统不去使用坏块。
根据所用的磁盘和控制器,对这些块有多种处理方式:
- 对于简单磁盘,如采用 IDE 控制器的磁盘,坏块可手动处理,如 MS-DOS 的 Format 命令执行逻辑格式化时会扫描磁盘以检査坏块。坏块在 FAT 表上会标明,因此程序不会使用它们。
- 对于复杂的磁盘,控制器维护磁盘内的坏块列表。这个列表在出厂低级格式化时就已初始化,并在磁盘的使用过程中不断更新。低级格式化将一些块保留作为备用,操作系统看不到这些块。控制器可以采用备用块来逻辑地替代坏块,这种方案称为扇区备用。
磁盘调度算法
磁盘的存取时间
一次磁盘读写操作的时间由寻道时间、旋转延迟时间和传输时间决定。
寻道(寻找)时间 $T_s$
将磁头移动到指定磁道所需时间。这个时间除跨越 $n$ 条磁道的时间外,还包括启动磁头臂的时间。
$T_s = s + m \times n$
$s$:磁臂启动时间,约为 2 ms。
$m$:与磁盘驱动器速度有关的常数,约为 0.2 ms。
$n$:跨越的磁道数。
旋转延迟时间 $T_r$
磁头定位到要读/写扇区所需的时间。一般取磁盘旋转一周所需时间的一半。
$T_r = \frac{1}{2r}$
$r$:磁盘的旋转速度,单位转/分,即 $T_r$ 取转半周的时间。
硬盘典型的旋转速度为 5400 转/分,即一周 11.1ms,则 $T_r$ 为 5.55ms。
对于软盘,其旋转速度为 300600 转/分,则 $T_r$ 为 50100ms。若站在存取一个文件的角度,旋转等待时间就与文件的物理结构有关,可以说旋转等待时间的多少取决于磁盘空闲空间的分配程序。
传输时间 $T_t$
从磁盘读出或向磁盘写入数据所经历时间。
$T_s = \frac{b}{rN}$
$b$:每次所读/写的字节数
$r$:磁盘的旋转速度
$N$:一个磁道上的字节数
即访问扇区时花费的旋转时间。
总平均存取时间 $T_a$
$T_a = T_s + T_r + T_t$
一般来说,寻道时间因为要移动磁臂,所以占用时间更长。
因此,在存储一个文件时,当一个磁道存储不下时,剩下部分一般存在同一个柱面上的不同盘面更好,避免磁臂移动,而不是存在同一个盘面的不同磁道。
实际意义不大,存取时间与磁盘调度算法密切相关,因为磁盘调度算法直接决定了寻道时间(旋转延迟时间和传输时间与磁盘转速线性相关)。
磁盘调度算法
以下算法的磁盘请求队列中的磁道请求顺序为:55、58、39、18、90、160、150、38、184,磁头初始位置处于 100 号磁道。
先来先服务 FCFS
根据进程请求访问磁盘的先后顺序进行调度。
若只有少量进程需要访问,且大部分请求都是访问簇聚的文件扇区,则有望达到较好的性能。
若有大量进程竞争使用磁盘,那么该算法在性能上往往接近于随机调度。
优点:简单;公平,不会导致磁臂黏着(只有 FCFS 不会导致磁臂黏着⚠)。
缺点:平均寻道距离大;仅应用在磁盘 I/O 较少的场合。
最短寻找时间优先 SSTF
选择与当前磁头所在磁道距离最近的磁道,以使每次的寻找时间最短。
优点:性能比 FCFS 算法好。
缺点:不能保证平均寻道时间最短;可能出现饥饿现象。
扫描 SCAN/电梯调度
在磁头当前移动方向上选择与当前磁头所在磁道距离最近的请求作为下一次服务的对象,严格地遵循从盘面的一端到另一端。
SSTF 算法产生饥饿的原因是 “磁头可能在一个小范围内来回地移动”。为了防止这个问题,可以规定:只有磁头移动到最外侧磁道时才能向内移动,移动到最内侧磁道时才能向外移动,这就是 SCAN 算法的思想。它是在 SSTF 算法的基础上规定了磁头移动的方向。
偏向于处理那些接近最里或最外的磁道的访问请求,对最近扫描过的区域不公平,因此它在访问局部性方面不如 FCFS 算法和 SSTF 算法好。
优点:寻道性能较好;可避免饥饿现象。
缺点:不利于远离磁头一端的磁道访问请求;在访问局部性方面不如 FCFS 算法和 SSTF 算法好。
循环扫描 C-SCAN
在 SCAN 算法基础上规定磁头单向移动来提供服务,回返时直接快速移动至起始端而不服务任何请求。
优点:消除了对两端磁道请求的不公平。
LOOK
对 SCAN 算法的改进,磁头移动只需要到达最远端的一个请求即可返回,不需要到达磁盘端点。称为 LOOK 调度是因为它们在朝给定方向移动前会查看是否有请求。
C-LOOK
和 LOOK 算法对 SCAN 算法的改进一样,C-LOOK 算法是对 C-SCAN 算法的改进。
⚠若无特别说明,默认 SCAN 算法和 C-SCAN 算法为改进后的 LOOK 和 C-LOOK 调度。
🌱总的来说,FCFS 算法太过简单,性能较差,仅在请求队列长度接近于 1 时才较为理想;SSTF 算法较为通用和自然;SCAN 算法和 C-SCAN 算法在磁盘负载较大时比较占优势。
减少延迟时间的方法
优化磁盘 I/O 效率,自然是从寻道时间、延迟时间和传输时间三方面考虑:
- 寻道时间靠磁盘调度算法减少;
- 传输时间是磁盘本身性质决定,无法通过一定的措施减少;
- 而延迟时间可以通过对盘面扇区进行交替编号和对磁盘片组中的不同盘面错位命名的方式减少。
交替编号
磁头读/写一个物理块后,需要经过短暂的处理时间才能开始读/写下一块,而磁盘是连续自转设备,不会停下来等待磁头处理,这使得磁盘转动一周很难读取到连续的物理块,故对一个盘面的扇区进行交替编号,即逻辑上相邻的扇区在物理上就不让它们相邻,于是读入多个连续块时就能减少延迟时间。
错位命名
由于磁盘的所有盘面是同步转动的,逻辑块在相同柱面上也是按盘面号连续存放的,即按 0 号盘 0 号扇区、0 号盘 1 号扇区、……、0 号盘 7 号扇区、1 号盘 0 号扇区、……、1 号盘 7 号扇区、2 号盘 0 号扇区……的顺序存放。要读入不同盘面上的连续块,在读完 0 号盘 7 号扇区后,还需要一段处理时间,所以当磁头首次划过 1 号盘 0 号扇区(下一次要读的块)时,并不能读取,只能等磁头再次划过该扇区时才能读取。为此,可对不同的盘面进行错位命名,则读入相邻两个盘面的连续块时也能减少延迟时间。
提高磁盘 I/O 速度的方法
文件的访问速度是衡量文件系统性能最重要的因素,可从以下三个方面来优化:
- 改进文件的目录结构及检索目录的方法,以减少对目录的査找时间。
- 选取好的文件存储结构,以提高对文件的访问速度。
- 提高磁盘 I/O 速度,以实现文件中的数据在磁盘和内存之间快速传送。
其中 1 和 2 已在 OS4 中介绍,这里主要介绍如何提高磁盘 I/O 的速度。
采用磁盘高速缓存
调整磁盘请求顺序
即上面介绍的各种磁盘调度算法。
提前读
在读磁盘当前块时,将下一磁盘块也读入内存缓冲区。
延迟写
仅在缓冲区首部设置延迟写标志,然后释放此缓冲区并将其链入空闲缓冲区链表的尾部,当其他进程申请到此缓冲区时,才真正将缓冲区信息写入磁盘块。
优化物理块的分布
除了上面介绍的扇区编号优化,当文件采用链接方式和索引方式组织时,应尽量将同一个文件的盘块安排在一个磁道上或相邻的磁道上,以减少寻道时间。
另外,将若干盘块组成簇,按簇对文件进行分配,也可减少磁头的平均移动距离。
虚拟盘
是指用内存空间去仿真磁盘,又叫 RAM 盘。常用于存放临时文件。
采用磁盘阵列 RAID
由于可采用并行交叉存取,因此能大幅提高磁盘 I/O 速度。
固态硬盘 SSD
见 CO3。
刷题总结
分配共享设备不会引起进程死锁。
缓冲区管理着重要考虑的问题是:实现进程访问缓冲区的同步。
在缓冲机制中,无论是单缓冲、多缓冲还是缓冲池,由于缓冲池是一种临界资源,所以在使用缓冲区时都有一个申请和释放(互斥)的问题需要考虑。
以下 I/O 操作都需要缓冲技术:
1)图形用户界面下使用鼠标
在鼠标移动时,若有高优先级的操作产生,等高优先级操作结束后,鼠标活动的数据可能会被后来的鼠标活动数据覆盖掉。所以为了记录鼠标活动的情况,必须使用缓冲技术。
2)多任务操作系统下的磁带驱动器(假设没有设备预分配)
磁带属于独占设备。进程请求 I/O 时,操作系统可以把 I/O 数据预先放入缓冲区,进程不必阻塞等待磁带分配。
3)包含用户文件的磁盘驱动器
块设备必须使用缓冲区,解决数据粒度不匹配的问题。可以设置缓冲区大小为一个块。
4)使用存储器映射 I/O,直接和总线相连的图形卡
为了便于多幅图形的存取及提高性能,缓冲技术是可以采用,特别是在显示当前一幅图形又要得到下一幅图形时,应采用双缓冲技术。
显存实际上就是显卡的缓冲区。
提高单机资源利用率的关键技术是多道程序设计技术
在单机系统中,最关键的资源是处理器资源,最大化地提高处理器利用率,就是最大化地提高系统效率。多道程序设计技术是提高处理器利用率的关键技术,其他均为设备和内存的相关技术。
SPOOLing 技术的重点:两大好处、三大软件。
驱动程序仅有一部分需要用汇编语言编写,其余部分可用高级语言编写。
要深刻理解缓冲区引入的几个目的。
光盘可以随机访问。
分区不属于逻辑格式化。
磁盘高速缓存位于内核空间。
缓冲区分为内核缓冲区和用户缓冲区。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 ZERO!