第六章 输入输出系统
文章目录
- 第六章 输入输出系统
- 6.1 I/O 系统的功能、模型和接口
- 6.1.1 I/O系统的基本功能
- 6.1.2 I/O系统的层次结构和模型
- 6.1.3 I/O系统接口
- 6.2 I/O设备和设备控制器
- 6.2.1 I/O 设备
- 6.2.2 设备控制器
- 6.2.3 内存映像 I/O
- 6.2.4 I/O通道
- 6.3 中断机构和中断处理程序
- 6.3.1 中断简介
- 6.3.2 中断处理程序
- 6.4 设备驱动程序
- 6.4.1 设备驱动程序概述
- 6.4.2 设备驱动程序的处理过程
- 6.4.3 对I/O设备的控制方式
- 6.5 与设备无关的 I/O 软件
- 6.5.1 与设备无关(Device Independence)软件的基本概念
- 6.5.2 与设备无关的软件
- 6.5.3 设备分配
- 6.5.4 逻辑设备名到物理设备名映射的实现
- 6.6 用户层的 I/O 软件
- 6.6.1 系统调用与库函数
- 6.6.2 假脱机(Spooling)系统
- 6.7 缓冲区管理
- 6.7.1 缓冲的引入
- 6.7.2 单缓冲区和双缓冲区
- 6.7.3 环形/循环缓冲区
- 6.7.4 缓冲池(Buffer Pool)
- 6.8 磁盘存储器的性能和调度
- 6.8.1 磁盘性能简述
- 6.8.2 早期的磁盘调度算法
- 6.8.3 基于扫描的磁盘调度算法
- 6.8.4 固态硬盘SSD
6.1 I/O 系统的功能、模型和接口
6.1.1 I/O系统的基本功能
方便用户使用I/O设备
- 隐藏物理设备的细节
- 与设备的无关性
提高CPU和I/O 设备的利用率
- 提高处理机和 I/O 设备的利用率
- 对 I/O 设备进行控制
为用户在共享设备时提供方便,并当系统发生错误时能及时发现错误,甚至于能自动修正错误。
- 确保对设备的正确共享
- 错误处理
1、隐藏物理设备的细节
🔍 I/O设备的多样性与复杂性
差异维度 | 示例 |
---|---|
数据传输速度 | 键盘、鼠标(低速) or 固态硬盘(Solid State Drive,简称 SSD)(高速) |
传输方向 | 输入设备(键盘、鼠标)、输出设备(显示器、打印机)、双向设备(网卡、USB设备) |
数据粒度 | 块设备-固定大小数据块(硬盘、SSD、U盘)、字符设备-每次操作1字节/字符(键盘、鼠标、串口) |
数据表示形式 | 文本(终端、打印机)、二进制(磁盘、GPU显存)、模拟信号(声卡) |
可靠性要求 | 医疗设备(高可靠性-不允许数据丢失) vs. 游戏外设(低可靠性-允许丢帧/延迟优化) |
粒度:设备在一次I/O操作中处理数据的最小单位大小,即每次读或写操作涉及的数据量
🔍 设备控制器(一种硬件设备): 不同的I/O设备 的设备控制器是不同的
⚙️
设备控制器的核心功能
功能 说明 示例场景 信号转换 将CPU的通用指令 → 设备专用操作(如磁头寻道、像素渲染)。 CPU发送 read()
→ 硬盘主控计算磁头位置。协议实现 遵循通信标准(如USB),处理数据包、校验和错误重传。 USB控制器解析HID协议读取鼠标位移。 缓冲管理 暂存数据以匹配速度差异(如网络卡的数据包缓冲)。 下载文件时网卡先存数据,再通知CPU处理。 错误处理 检测并纠正设备错误(如硬盘ECC纠错、打印机缺纸报警)。 SSD主控发现坏块后自动映射到备用区块。 中断与DMA 通过中断或DMA(直接内存访问)减少CPU负担。 显卡渲染完一帧后通过中断通知CPU。 电源管理 控制设备功耗(如硬盘休眠、USB设备挂起)。 笔记本合盖时USB控制器关闭外设供电。 ⚙️
设备控制器的核心模块
寄存器组(Registers)
控制寄存器(Command Register):接收CPU指令(如“启动读操作”)。
状态寄存器(Status Register):反馈设备状态(如“忙碌中”“已就绪”)。
数据寄存器(Data Register):暂存传输的数据(如键盘输入的ASCII码)。
地址寄存器(Address Register):指定数据在设备上的存储位置(如硬盘LBA地址)。
接口电路(Interface Circuit)
:实现信号转换。
控制逻辑(Control Logic)
:解析CPU指令,生成设备能理解的底层操作。
缓冲区(Buffer/Cache)
:临时存储数据,缓解 CPU高速 与 设备低速 之间的速度差异(如打印机的行缓冲)。
中断控制器(IRQ Handler)
:设备完成任务时触发中断,通知CPU(如“打印完成”)。
🔍 设备驱动程序(一种软件模块):不同的I/O设备的设备驱动程序是不同的
对设备适当的抽象,以隐藏掉物理设备的实现细节,方便用户使用:通过调用标准接口触发设备驱动程序,驱动再将通用操作翻译成控制器专属命令。
设备初始化 | 检测设备、分配资源(内存、IRQ)、加载固件(Firmware)。 | 开机时加载显卡驱动并初始化显存。 |
---|---|---|
命令转换 | 将OS通用API(如read() /write() )→ 设备专用指令。 | fopen() → 硬盘控制器的LBA寻址。 |
数据传输 | 管理内存与设备间的数据流动(DMA/轮询/中断)。 | 网卡驱动通过DMA将数据包送入内存。 |
中断处理 | 响应设备中断(如硬盘I/O完成、键盘按键)。 | 用户按下键盘时触发中断并上报键码。 |
电源管理 | 控制设备休眠/唤醒(如USB设备挂起)。 | 笔记本合盖时WiFi驱动关闭射频模块。 |
错误处理 | 检测设备错误(如磁盘坏道),尝试恢复或上报OS。 | SSD驱动发现CRC错误后触发重传。 |
🔍 对比表格:设备控制器 vs 设备驱动程序
驱动负责统一接口,控制器负责硬件执行。
对比维度 | 设备控制器 | 设备驱动程序 |
---|---|---|
存在形式 | 物理芯片(ASIC/FPGA) | 软件代码(.ko/.sys/.dll文件) |
位置 | 硬件设备内部(如显卡PCB上的GPU芯片) | 操作系统内核/用户空间 |
核心功能 | 向下统一硬件信号(处理指令 → 电信号的转换) | 向上对OS提供统一接口(处理OS接口 → 硬件指令的转换) |
标准化程度 | 厂商私有 | 遵循OS接口标准 |
更新方式 | 固件升级(需刷写芯片) | 软件安装(可热加载) |
崩溃影响 | 硬件故障(可能导致设备损坏) | 系统蓝屏/内核panic(软件级错误) |
2、与设备的无关性 - 设备独立性软件
动态驱动绑定(Dynamic Driver Binding) :系统可以为新I/O设备自动安装和寻找驱动程序 - 即插即用,无需手动配置驱动。
- 设备插入时:操作系统根据
Class Code
自动匹配并加载驱动。
例如:在USB接口插入一个设备时(如U盘、鼠标、键盘等),系统能够自动识别并配置该设备【程序无需关心是哪种类型设备】 - 驱动卸载时:释放资源,应用程序收到错误(如
ENODEV
),但无需修改代码逻辑。
逻辑设备名(Logical Device Name)
操作系统为不同设备类型提供统一的入口(设备文件):【程序无需关心是同类型设备的牌子是否不同】
- 存储设备 →
/dev/sd*
。 - 打印机 →
/dev/lp0
。 - 输入设备 →
/dev/input/event*
。
程序无需修改代码:
读硬盘:
read("/mnt/usb/data.txt")
(文件系统自动路由到U盘)。读鼠标:
read("/dev/input/event2")
(输入子系统返回移动事件)。更换打印机
物理操作:用户将USB打印机从HP换成Canon。
系统行为:
- 新打印机返回
Class 0x07
(打印机类)。- OS卸载旧驱动,加载
canon-ppd
驱动,仍映射到/dev/lp0
。程序无感:继续向
/dev/lp0
写入数据,由新驱动处理。
3、提高处理机和 I/O 设备的利用率
在一般的系统中,许多I/O设备间
是相互独立的,能够并行
操作;在处理机与设备之间
也能并行
操作。
- 要求处理机能快速响应用户的I/O请求,使I/O设备尽快地运行起来;
- 尽量减少在每个I/O设备运行时处理机的干预时间。
4、对 I/O 设备进行控制
目前对 I/O 设备有四种控制方式:
- ①
采用轮询的可编程 I/O 方式
- ②
采用中断的可编程 I/O 方式
—— 打印机、键盘终端等低速设备 - ③
直接存储器访问方式
—— 磁盘、光盘等高速设备 - ④
I/O 通道方式
。
5、确保对设备的正确共享
从设备的共享属性上,可将系统中的设备分为如下两类:
独占设备
,进程应互斥地访问这类设备,即系统一旦把这类设备分配给了某进程后,便由该进程独占,直至用完释放。【打印机】共享设备
,是指在一段时间内允许多个进程同时访问的设备。【磁盘】。
6、错误处理
从处理的角度,可将错误分为**临时性错误 和 持久性错误**。
- 对于
临时性错误
,可通过重试操作来纠正, - 发生了
持久性错误
时,才需要向上层报告。
在低层软件能够解决的错误就不向上层报告,只有低层软件解决不了的错误才向上层报告,请求高层软件解决。
6.1.2 I/O系统的层次结构和模型
1、I/O 软件的层次结构
用户层 I/O 软件,实现与用户交互的接口
,用户
可直接调用
该层所提供的与I/O操作有关的库函数
对设备进行操作。
设备独立性软件 / 系统调用处理层,用于实现用户程序与设备驱动的统一接口
、设备命名(逻辑设备名,物理设备名)
、设备的保护
以及设备的分配与回收
等,同时为设备管理和数据传送提供必要的存储空间 - 缓冲区
。
设备驱动程序,与硬件
直接相关,用于具体实现系统对设备发出的操作指令,驱动I/O设备工作
的驱动程序。
注:驱动程序一般会以一个独立进程的方式存在
中断处理程序,用于保存被中断进程的CPU环境
,转入相应的中断处理程序进行处理
,处理完毕再恢复被中断进程的现场后
,返回到被中断的进程
。
特性 | 普通缓冲(Buffering) | 磁盘 Spooling |
---|---|---|
存储位置 | 内存(RAM) | 磁盘 |
速度 | 极快(适合高速设备) | 较慢(适合慢速外设) |
持久性 | 临时性(进程结束即丢失) | 持久性(断电不丢失)- 打印队列、邮件队列 |
2、I/O 系统中各种模块之间的层次视图
6.1.3 I/O系统接口
1、块设备接口
🏷️ 块设备概述
- 🔍 定义:以
固定大小的数据块
为单位进行存取和传输的设备(如 💽磁盘、📀光盘)。- ⚡
传输速率
:通常每秒 数MB ~ 数十MB(高速传输
)。 - 🎯
寻址方式
:支持随机读写
,可直接访问任意数据块地址(逻辑块号 ➔ 物理位置)。 - 🚀
I/O 方式
:通常采用DMA(直接内存访问)
,减少 CPU 开销。
- ⚡
- 💡 典型设备:硬盘(HDD)、固态硬盘(SSD)。
🏷️ 块设备特点
- 磁盘结构的抽象化(一维 vs 二维)
- 📊 物理结构:磁盘采用
二维寻址
(磁道号 + 扇区号)。 - 🎚️ 块设备接口:将其转换为
一维线性序
列(0 ~ n-1 扇区编号)。 - 📍 优点:上层无需关心磁头移动、磁道计算,只需指定逻辑块号即可访问数据。
- ⚠️ 隐藏细节:屏蔽底层复杂性,让系统以 顺序存储 的方式操作磁盘。
- 📊 物理结构:磁盘采用
- 命令映射与底层操作
- 📜 高层命令:
open()
(打开)、read()
(读取)、write()
(写入)、close()
(关闭)。 - 🔧 底层转换:
- 读取文件时,逻辑块号(LBN)➔ 物理扇区(盘面、磁道、扇区)。
- 写入时,数据被组织成块,并映射到磁盘的对应位置。
- 🌉 作用:抽象文件系统与物理设备之间的交互,提供统一接口。
- 📜 高层命令:
- 与虚拟存储器的配合(缺页处理)
- 💾 缺页中断:
- 🚨 进程访问的页面不在内存 ➔ 触发 Page Fault(缺页中断)。
- 🔄 块设备接口
从磁盘读入缺失页
(换入操作)。
- ⚙️ 关键角色:
链接磁盘和内存
,使虚拟内存能动态 交换数据页。- 让进程认为自己拥有 比物理内存更大的地址空间。
- 💾 缺页中断:
2、流设备 / 字符设备 接口
🏷️ 流设备(字符设备)概述
- 🔍 定义:以
字符(字节)
为单位进行数据传输的设备(如 ⌨️键盘、🖨️打印机、📡串口)。- ⚡ 传输速率:通常 几个字节 ~ 几千字节/秒(
较低
)。 - 🚫
不可寻址
:无法随机访问,输入/输出只能是顺序流式数据
。 - 🚨 I/O 方式:通常采用
中断驱动(Interrupt-Driven I/O)
,由设备触发 CPU 处理数据。
- ⚡ 传输速率:通常 几个字节 ~ 几千字节/秒(
- 💡 典型设备:键盘、鼠标、终端、串口、打印机等。
🏷️ 流设备特点
-
数据存取方式:
get()
和put()
操作-
📥
get()
操作:- 从
字符缓冲队列
读取一个字符
并返回给调用者
(内存)。 - 若缓冲区为空,则等待设备输入(如键盘按键)。
- 从
-
📤
put()
操作:- 向
字符缓冲队列
写入一个字符
,等待设备输出(如打印)。
- 向
-
💾
缓冲区管理
:由于字符设备不支持随机访问,通常需维护 FIFO 字符缓冲队列:- 输入时,设备数据流顺序存入缓冲区(如串口接收)。
- 输出时,缓冲区数据依次发送到设备(如终端显示)。
-
-
通用控制指令:
ioctl()
(Input/Output Control):-
因字符设备 种类繁多且差异大,接口
提供通用控制指令
。 -
参数化配置:
每个参数
对应设备特定的功能
(如调整串口波特率、清空打印队列)。
-
-
独占性与设备管理
- 🚧
独占设备
:大多数字符设备(如打印机)一次仅允许一个进程访问
。 - 互斥机制:
- 进程需先
open()
打开设备,若设备已被占用则失败。 - 使用完毕后需
close()
关闭设备 释放资源。
- 进程需先
- 🚧
⚙️ 字符设备 vs 块设备对比
特性 | 字符设备 🖨️⌨️ | 块设备 💽📀 |
---|---|---|
传输单位 | 字符(字节) | 数据块(如 4KB) |
寻址能力 | ❌ 不可寻址(顺序访问) | ✅ 可寻址(随机访问) |
传输速率 | 低(字节级) | 高(MB/s 级) |
I/O 方式 | 中断驱动 | DMA(直接内存访问) |
典型设备 | 键盘、打印机、串口 | 硬盘、SSD、光盘 |
3、网络通信接口
网络连接基础
- 🖥️ 物理接入:计算机需通过 网卡(NIC)、Wi-Fi、蓝牙 等硬件连接到网络。
- 📡 协议栈支持:操作系统需实现 TCP/IP协议栈(或其他网络协议),提供数据包收发能力。
- ⚙️ 驱动程序:OS需为网卡提供驱动,管理底层硬件(如中断处理、DMA传输)。
网络软件支持
- 🔗 协议实现:支持 IP(网络层)、TCP/UDP(传输层)、HTTP/FTP(应用层) 等协议。
- 📂 网络文件系统(NFS/SMB):允许远程访问文件。
- 🌀 网络服务:内置 DHCP(自动分配IP)、DNS(域名解析)、防火墙 等功能。
网络通信接口
- 📡 Socket API:通用编程接口(如
socket()
、bind()
、listen()
),支持 TCP/UDP通信。 - 🌐 高层抽象:
- 提供
curl
、wget
等工具,简化HTTP请求。 - 浏览器依赖OS的 Socket接口 访问互联网。
- 提供
6.2 I/O设备和设备控制器
I/O 设备一般是由执行 I/O 操作的机械部分和执行控制 I/O的电子部件组成。
执行 I/O 操作的机械部分【主要用来执行具体I/O操作】
就是一般的 I/O 设备
执行控制 I/O 的电子部件【通常是一块插入主板扩充槽的印刷电路板】
则称为设备控制器或适配器
(adapter)。
6.2.1 I/O 设备
“I/O”就是“输入/输出”(Input/Output)
I/O设备就是可以将数据输入到计算机
,或者可以接收计算机输出数据的外部设备
,属于计算机中的硬件部件。
1、I/O 设备的类型
按使用特性分类
- 第一类是
存储设备
,也称外存、辅存
,是用以存储信息
的主要设备。该类设备存取速度较内存慢,但容量却大得多,价格也便宜。 - 第二类是
I/O设备
,它又可分为输入设备、输出设备和交互式设备。输入设备
用来接收外部信息
,如键盘、鼠标、扫描仪、视频摄像等。输出设备
用于将计算机处理后的信息送向处理机外部的设备
,如打印机、绘图仪等。交互式设备
则是指集成的上述两类设备
,主要是用于同步显示用户命令以及命令执行的结果。
- 第三类是
网络通信设备
:调制解调器等
按传输速率分类
- 第一类是
低速设备
,其传输速率仅为每秒钟几个字节至数百个字节。典型的低速设备有键盘、鼠标
。 - 第二类是
中速设备
,其传输速率在每秒钟数千个字节至数十万个字节。典型的中速设备有行式打印机、激光打印机
等。 - 第三类是
高速设备
,其传输速率在数十万字节至千兆字节。典型的高速设备有磁带机、磁盘机、光盘机
等。
按信息交换的单位分类
- 块设备:传输速率较高,可寻址,即对它可随机地读/写任一块
- 字符设备:传输速率较慢,不可寻址,在输入/输出时常采用中断驱动方式
2、设备与控制器之间的接口
设备并不是直接与 CPU 进行通信, 而是与设备控制器通信。因此,在 I/O设备中应含有与设备控制器间的接口
,在该接口中有三种类型的信号。
数据信号线
。用于在设备和设备控制器之间传送数据信号。- 对
输入设备
而言,由外界输入的信号经转换器
转换后,所形成的数据通常先送入缓冲器
中,当数据量达到一定的比特(字符)数后,再从缓冲器
通过一组数据信号线传送给设备控制器
。 - 对
输出设备
而言,则是将从设备控制器经过数据信号线传送来的一批数据先暂存于缓冲器
中,经转换器
作适当转换后,再逐个字符地输出。
- 对
控制信号线
。由设备控制器向I/O设备发送控制信号时的通路。规定了设备将要执行的操作
,如读操作(指由设备向控制器传送数据)或写操作(从控制器接收数据),或执行磁头移动等操作。状态信号线
。该信号线**用于传送指示设备当前状态的信号
**。设备的当前状态有正在读(或写); 设备已读(写)完成,并准备好新的数据传送。
6.2.2 设备控制器
- 设备控制器的主要功能是,
控制一个或多个I/O设备
,以实现I/O设备和计算机之间的数据交换
。是CPU 与 I/O设备之间的接口
,接收从 CPU 发来的命令,去控制I/O 设备工作。 - 设备控制器是一个
可编址的设备
:- 当仅
控制一个设备
时,它只有一个唯一的设备地址; - 若控制器可
连接多个设备
,则应含有多个设备地址,每一个设备地址对应一个设备。
- 当仅
- 可把设备控制器分成两类: 一类是用于
控制字符设备
的控制器,另一类是用于**控制块设备
**的控制器。
1、设备控制器的基本功能
🔧 1. 接收和识别命令
- 功能:
接收CPU发送的控制命令
(如read
、write
等),并解析执行
。 - 关键组件:
控制寄存器
:存放命令编码和参数。命令译码器
:解析CPU指令,转换为设备可执行的操作。
🔄 2. 数据交换
-
功能:
CPU ↔ 控制器
:通过数据总线并行传输
数据。控制器 ↔ 设备
:按设备速率传输数据。
-
关键组件:
数据寄存器
:暂存传输的数据。 -
数据流向:
📊 3. 设备状态管理
- 功能:
- 记录
设备的实时状态
(如“就绪”、“忙”、“错误”),供CPU查询。 - CPU通过
轮询或中断
获取状态。
- 记录
- 关键组件:
状态寄存器
:位字段表示不同状态(如Bit 0=1表示“设备就绪”)。
📍 4. 地址识别
- 功能:
- 识别CPU访问的
设备地址
和寄存器地址
。 - 每个设备/寄存器需唯一地址(类似内存地址)。
- 识别CPU访问的
- 关键组件:
地址译码器
:将CPU发出的地址转换为设备片选信号。
📦 5. 数据缓冲(Buffer)
- 功能:
速度匹配
:缓存高速CPU与低速I/O设备间的数据
。- 输出:CPU快速写入缓冲区 → 控制器按设备速率发送。
- 输入:设备数据暂存缓冲区 → CPU批量读取。
平滑流量
:避免数据丢失或CPU阻塞等待。
- 实现方式:
硬件缓冲区
(FIFO)DMA传输
:直接内存访问绕过CPU。
❌ 6. 差错控制
- 功能:
检测数据传输中的错误
(如奇偶校验、CRC校验)。- 发现错误时
置位状态寄存器
并通知CPU重传。【将差错检测码置位,并向CPU报告,CPU将本次传送来的数据作废,并重传】
- 常见校验方式:
奇偶校验
:验证数据中1的个数是否为偶数/奇数。循环冗余校验(CRC)
:适用于网络和存储设备。
2、设备控制器的组成
-
设备控制器与处理机的接口。该接口用于实现CPU与设备控制器之间的通信,在该接口中共有三类信号线:数据线、地址线和控制线。
- 数据线通常与两类寄存器相连接:
- ① 第一类是
数据寄存器
,在控制器中可以有一个或多个数据寄存器,用于存放从设备送来的数据
(输入),或从 CPU送来的数据
(输出)。 - ②第二类是
控制/状态寄存器
,在控制器中可以有一个或多个这类寄存器,用于存放从CPU送来的控制信息或设备的状态信息
。
- ① 第一类是
- 数据线通常与两类寄存器相连接:
-
设备控制器与设备的接口。在一个设备控制器上,可以连接一个或多个设备 <==> 在控制器中便有一个或多个设备接口。在
每个接口中都存在数据、控制和状态三种类型的信号
。控制器中的I/O逻辑
根据处理机发来的地址信号
去选择一个设备接口
。 -
I/O 逻辑。
I/O 逻辑用于实现对设备的控制
。通过一组控制线与处理机交互,处理机利用该逻辑向控制器发送 I/O命令。每当
CPU要启动一个设备
时,一方面将启动命令发送给控制器
,另一方面又同时通过地址线把地址发送给控制器
,由控制器的I/O逻辑对收到的地址进行译码
,再根据所译出的命令对所选设备进行控制
。
6.2.3 内存映像 I/O
驱动程序
将抽象I/O 命令
转换
出的一系列具体的命令、参数等
数据装入
设备控制器的相应寄存器
,由控制器来执行这些命令
,具体实施对 I/O 设备的控制。
设备驱动程序写入设备控制器寄存器的两个方法:
1、利用特定的 I/O 指令 - 寄存器独立编址
-
基本原理
-
为每个设备控制器的
寄存器分配独立的I/O端口地址
(8位或16位整数)。 -
使用
专用的I/O指令访问设备寄存器,与内存访问指令区分开
。
-
-
指令示例
; 将CPU寄存器内容写入设备控制器寄存器 io-store cpu-reg, dev-no, dev-reg ;cpu-reg:CPU的某个寄存器, dev-no:设备号 - 控制器,dev-reg:控制器寄存器号 ; 将CPU寄存器中的内容写入内存指令 store cpu-reg, k ; k:内存地址
-
特点
优点 缺点 1. 硬件设计简单(地址分离) 1. 需要专用指令,增加编程复杂性
【访问内存和访问设备需要两种不同的指令】2. 安全性高(隔离I/O和内存) 2. 指令集依赖 -
应用场景
:早期计算机(如IBM大型机)、x86架构的低层硬件控制。
2、内存映像 I/O
-
基本原理
-
统一编址
:将设备控制器寄存器映射到内存地址空间
。- 地址
0~n-1
:物理内存
。 - 地址
≥n
:设备寄存器
(如n
对应控制器0的第一个寄存器)。
- 地址
-
使用**
普通内存读写指令
**(如load
/store
)访问设备寄存器。
-
-
指令示例
; 将CPU寄存器内容写入设备控制器寄存器(地址n) store cpu-reg, n ; n:控制器寄存器映射的内存地址
-
特点
优点 缺点 1. 简化了指令。可以采用对内存进行操作的指令来对控制器进行操作(与内存操作一致) 1. 占用内存地址空间 2. 支持更多寻址模式,适合高性能场景(如DMA) 2. 需要硬件地址译码支持 -
应用场景
: 现代计算机(如ARM、RISC-V)、 显卡显存 (如/dev/mem
)、嵌入式系统。
🆚 核心对比
特性 | 特定I/O指令 - 寄存器独立编址 | 内存映射I/O |
---|---|---|
地址空间 | 独立I/O端口 | 与内存共享地址空间 |
指令类型 | 专用指令(如in/out ) | 通用内存指令(如mov ) |
性能 | 较低(需额外译码) | 较高(可利用缓存) |
硬件复杂度 | 简单 | 复杂(需地址映射逻辑) |
典型架构 | x86 | ARM、RISC-V |
6.2.4 I/O通道
核心目标:通过 在CPU和设备控制器之间
增设I/O通道
,进一步减少CPU对I/O操作的干预
,实现更高程度的I/O并行化,从而提升系统整体效率。
1、I/O通道设备的引入
问题背景
设备控制器虽能处理部分I/O任务(如数据缓冲、错误检测),但以下场景仍会加重CPU负担:
- 主机
连接大量外设
时,频繁中断
和状态轮询
消耗CPU资源。 复杂的I/O操作
(如多设备协同、数据分块传输)需要CPU参与组织。
I/O通道的解决方案
- 角色:I/O通道是
介于CPU和设备控制器之间
的 特殊处理机
,负责独立管理I/O任务。 - 核心功能:
接收CPU的I/O指令
,自主从内存加载并执行通道程序
(Channel Program)。- 完成I/O操作后,通道向CPU发送
中断信号
,实现异步处理。
特性 | 说明 |
---|---|
指令单一性 | 仅支持与I/O相关的指令 (如数据传输、设备控制),指令集比通用CPU简化。 |
无独立内存 | 通道程序存放在主机内存中,与CPU共享内存空间 (通过MMU映射访问)。 |
并行能力 | 多个通道可同时工作 ,CPU只需初始化任务,实现真正的I/O与计算重叠。 |
2、通道类型
-
字节多路通道(Byte Multiplexor Channel)——按字节交叉方式工作的通道
核心组成
组件 说明 主通道 物理上的高速数据传输通路,由所有子通道分时共享。 非分配型子通道 每个子通道独立连接一台I/O设备(数量可达几十到数百个), 不独占主通道,按时间片轮转方式共享主通道
。🛠️ 工作流程
字节级轮转:子通道依次占用主通道,
每次仅传输1字节数据
,完成后立即释放主通道
。防数据丢失条件:通道扫描速率 > 设备数据生成速率:确保在轮转周期内能处理每个设备的字节数据。
🛠️ 关键特性——时间片分配机制
- 固定时间片:每个子通道获得均等的极短时间片(微秒级),严格按轮转顺序切换。
- 无优先级区分:所有子通道平等共享带宽,适用于低速设备(如终端、串口打印机)。
-
数组选择通道(Block Selector Channel)
📌 基本概念
-
功能:负责大块数据的高速传输,适用于独占式高速 I/O 设备。
同一时间只能服务一个设备,只有当前设备的 I/O 操作完成后,才能切换到下一个设备。
⚙️ 关键特征
独占式访问 - 通道利用率很低
一次只能连接一个控制器/设备
,直到操作完成。无法并发处理多个 I/O 请求
。
适用于大数据块传输
- 适合
磁带、磁盘
等需要连续读写的设备。 不适合低速设备
(如键盘、打印机)。
- 适合
-
-
数组多路通道(Block Multiplexor Channel)
📌 基础概念
- 设计目标:弥补字节多路通道(低速设备)和数组选择通道(独占式高速设备)之间的不足,实现多设备块数据并行传输。
⚙️ 关键特性
-
分块并行传输
:-
不同于字节多路通道的「逐字节切换」,数组多路通道
以数据块(Block)为单位切换
例:设备 A 传输 512B 数据块 → 切换至 设备 B → 传输其 512B 数据块 → 再返回 设备 A……
-
优势:减少了通道切换开销,提高吞吐量。
-
-
支持多设备并发
:-
同一通道可挂接 多个设备
。 -
逻辑上并行,物理上仍串行(通过时间片分时复用)。
-
特性 | 字节多路通道 | 数组选择通道 | 数组多路通道 |
---|---|---|---|
传输单位 | 1字节(交替) | 数据块(连续) | 数据块(交替) |
子通道类型 | 非分配型(共享) | 分配型(独占) | 非分配型(共享) |
适用设备 | 低速字符设备 | 高速块设备(如磁盘) | 中高速块设备(如磁带) |
并行能力 | 高(多设备交错) | 低(单设备独占) | 中(多设备分块交替) |
3、“瓶颈”问题
6.3 中断机构和中断处理程序
6.3.1 中断简介
1、中断和陷入
中断和陷入的主要区别是信号的来源,即是来自CPU外部,还是 CPU 内部。
- 外中断或中断
- 中断是指
CPU 对 I/O 设备发来的中断信号的一种响应
。是由外部设备引起
的,故又称外中断。 - CPU 暂停正在执行的程序,保留 CPU 环境后,自动地转去
执行该 I/O 设备的中断处理程序
。执行完后,再回到断点,继续执行原来的程序。
- 中断是指
- 内中断或陷入(trap)
- 由
CPU内部事件所引起的中断
,例如进程在运算中发生了上溢或下溢、程序出错如非法指令、地址越界,以及电源故障等。 - 若系统发现了有陷入事件,CPU也将暂停正在执行的程序,转去
执行该陷入事件的处理程序
。
- 由
2、中断向量表和中断优先级
-
中断向量表
-
为每种设备配以相应的中断处理程序,并把该程序的入口地址放在中断向量表的一个表项中,并为每一个设备的中断请求规定一个中断号,它直接对应于中断向量表的一个表项中。
-
-
中断优先级
经常会有多个中断信号源,每个中断源对服务要求的紧急程度并不相同,为此,系统就需要为它们分别规定不同的优先级。
3、对多中断源的处理方式
对于多中断信号源的情况,当处理机正在处理一个中断时,又来了一个新的中断请求,可有两种处理方式:屏蔽(禁止)中断与嵌套中断。
-
屏蔽(禁止)中断
- 当处理机
正在处理一个中断
时,将屏蔽掉所有的中断
,即处理机对任何新到的中断请求,都暂时不予理睬,而让它们等待。直到处理机已完成本次中断的处理后,处理机再去检查是否有中断发生
。若有,再去处理新到的中断,若无,则返回被中断的程序。 - 在该方法中,
所有中断都将按顺序依次处理
。 - 优点是
简单
,但不能用于对实时性要求较高的中断请求
。
- 当处理机
-
嵌套中断
在设置了中断优先级的系统中,通常按这样的规则来进行优先级控制:-
当同时有多个不同优先级的中断请求时,
CPU 优先响应最高优先级的中断请求
; -
高优先级的中断请求可以抢占正在运行的低优先级中断的处理机
。例子:
- 处理机正在处理打印机中断,当有磁盘(磁盘优先级高于打印机的优先级)中断到来时,可暂停对打印机中断的处理,转去处理磁盘中断。
- 处理机正在处理打印机中断,当有键盘(键盘优先级低于打印机的优先级)中断到来时,处理机继续处理打印机中断。
-
6.3.2 中断处理程序
中断处理程序的处理过程可分成以下几个步骤
-
📝 测定是否有未响应的中断信号
-
中断信号产生条件
- 设备控制器在完成
单个字符/字/数据块
的输入
(如键盘按键)或输出
(如打印机数据传输)后,主动向处理机(CPU)发送 中断请求信号。 - 举例:
- 读入数据:磁盘控制器读取完一个扇区后,请求CPU将数据传送到内存缓冲区。
- 输出数据:网卡缓冲区空时,请求CPU填充待发送的数据包。
- 设备控制器在完成
-
处理机对中断的检测
每条指令执行完毕后
,CPU会检查是否有 未响应的中断信号。- 检测顺序:执行完当前指令 → 查询中断信号 → 若无中断,继续下一条指令;若有中断,停止原有进程的执行,准备转去执行中断处理程序,为把处理机的控制权转交给中断处理程序做准备。
-
-
📝 保护被中断进程的 CPU 环境
- 📌 核心目标:确保中断处理结束后,被中断的进程能 精确恢复执行,如同未被中断过。
- ✨保存内容:
从中断现场恢复到当前进程运行所需要的信息
。通常由硬件自动将 处理机状态字(PSW) 和保存在 程序计数器(PC)中下一条指令的地址
保存在中断保留区(栈)中。【指令在N位置时被中断的,程序计数器中的内容为N+1】把被中断进程的 CPU 现场信息
,即将包括 所有 CPU 寄存器 的(如通用寄存器、段寄存器等)内容都压入中断栈中。
-
📝 转入相应的设备处理程序
- 由处理机对各个中断源进行测试,以
确定引起本次中断的 I/O设备
- 向提供中断信号的设备
发送确认信号
- 在该
设备收到确认信号后
,就立即取消它所发出的中断请求信号
- 将相应的
设备中断处理程序的入口地址装入到程序计数器
中。【当处理机运行时,便可自动地转向中断处理程序】
- 由处理机对各个中断源进行测试,以
-
📝 中断处理
-
不同的设备,有不同的中断处理程序。
程序首先从设备控制器中读出设备状态
,以判别本次中断是正常完成中断还是异常结束中断。-
✅若是
正常完成中断
,处理数据或结束操作。(如数据就绪📥、操作成功✔️)。字符设备的读操作:
🔹中断来 → 读数据 → 存缓冲 → 指针+1 → 需要就再来一轮
🔹设备触发中断
🔔:设备(如键盘)读到一个字符,放进数据寄存器,然后发中断CPU处理数据
🚀
- 取数据:CPU从设备寄存器读走字符。
- 存缓冲:把字符塞进内存缓冲区。
- 移指针:缓冲区指针往后挪一格,使其指向下一个内存单元。
后续操作(可选)
🔄:如果还要继续读,可再向控制器发送新的命令,进行新一轮的数据传送。
-
❌若是
异常结束中断
,则根据发生异常的原因做相应的处理。(如设备错误💥、超时⏱️)。
-
-
-
📝 恢复CPU的现场并退出中断 :中断处理完成后,CPU 需要恢复之前的状态(现场),并决定 下一步执行哪个程序。
关键因素
:-
中断屏蔽(禁止)方式?
🚫如果中断被屏蔽(关中断),处理完成后 直接返回被中断的进程。需完成以下步骤:
从栈中恢复现场
🗃️- 弹出 程序计数器(PC) → 获取下一条指令地址(
N+1
)。 - 恢复 处理机状态字(PSW) → 还原 CPU 执行权限(用户态/内核态)。
- 恢复 通用寄存器 & 段寄存器 → 复原程序执行时的数据环境。
- 弹出 程序计数器(PC) → 获取下一条指令地址(
执行 IRET(中断返回指令)
⬅️:CPU 依据恢复的PC
和PSW
,跳转回N+1
继续执行原程序。
-
中断嵌套方式?
🏗️(允许更高优先级中断抢占):无更高优先中断
➝ 返回被中断进程。有更高优先中断
➝ 先处理新中断(继续嵌套)。
-
6.4 设备驱动程序
6.4.1 设备驱动程序概述
1、设备驱动程序的功能
📌接收并转换命令(抽象→具体)
- 核心任务:
接收
由与设备无关的软件发来的命令和参数
如read(fd, buf, size)
)。→ 解析请求 →转换
为设备相关的底层操作序列
📌 检查状态与初始化设备
- 1️⃣
合法性检查
:用户请求是否越界?(如读取超出磁盘容量) - 2️⃣
设备状态检查
:设备是否就绪?有无故障? - 3️⃣
配置设备
:设置工作模式(如波特率、DMA传输)、传递参数(如磁盘扇区号)。
📌 启动I/O或排队等待
- 🟢
设备空闲
——立即启动
I/O 设备,完成指定的 I/O 操作
- 🔴
设备忙碌
——将请求者的请求块挂在设备队列上等待
📌 处理设备中断
- 及时
响应
由设备控制器发来的中断请求
,并根据其中断类型
,调用相应的中断处理程序
进行处理。
2、设备驱动程序的特点
- 它将
抽象的 I/O 请求
转换成具体的 I/O 操作
后传送给控制器
。又把控制器中所记录的设备状态
和I/O 操作完成情况
,及时地反映给请求 I/O的进程
。 - 对于
不同类型的设备,应配置不同的驱动程序
。但可以为相同的多个终端设置一个终端驱动程序
。 - 常用的 I/O 控制方式是
中断驱动
和DMA 方式
。 - 由于驱动程序与硬件紧密相关,因而其中的一部分必须用汇编语言书写。目前有
很多驱动程序的基本部分已经固化在 ROM 中
。 - 一个
正在运行的驱动程序
常会在一次调用完成前被再次调用
。
3、设备处理方式
分成三类:
-
每类设备一个专用进程:
每类设备
(如打印机、终端、磁盘)分配**一个专属进程
**,专门处理其I/O请求(读/写/控制)。优点 缺点 高并发性(设备间并行) 进程数多,内存开销大 故障隔离(单一设备崩溃不波及其他) 进程切换开销可能较高 -
全局单一I/O进程:
整个系统
仅用1个I/O进程
(或拆分为输入进程+输出进程)处理所有设备操作。优点 缺点 节省内存(减少进程数量) 单点瓶颈(所有I/O串行化) 简化调度(无进程间竞争) 设备故障可能影响全局 -
无专用进程(驱动调用式):
不设常驻I/O进程
,仅为每类设备编写**驱动模块
,由用户进程或内核线程**直接调用。优点 缺点 灵活性高(驱动可动态加载) 用户进程可能因I/O阻塞 减少常驻进程开销 需处理并发调用(同步机制)
6.4.2 设备驱动程序的处理过程
将抽象要求转换为具体要求
- 用户及上层软件对设备控制器的具体情况毫无了解,因而只能发出操作指令——
抽象要求
- 在每个设备控制器中都含有若干个寄存器,分别用于暂存命令、参数和数据等——
具体要求
在OS中只有驱动程序同时了解抽象要求和设备控制器中的寄存器情况
,也只有驱动程序知道命令、数据和参数应分别送往哪个寄存器。
请求校验(Validation)
操作合法性检查
: 阻止设备不支持的请求(如从打印机读取数据)- 常见非法请求:
权限冲突
:以只读模式打开设备后尝试写入。功能不符
:向输出设备(如显示器)发送读请求。
- 处理方式:
驱动返回错误码
(如-EPERM
、-EINVAL
)。I/O 系统决定是否终止进程或仅警告
(如继续运行但忽略请求)。
- 常见非法请求:
参数有效性检查
: 如磁盘请求的扇区号是否越界等
检查设备状态
- 启动某个设备进行I/O操作,其前提条件应是该
设备正处于就绪状态
。 - 在
每个设备控制器中,都配置有一个状态寄存器
。 - 驱动程序在启动设备之前,先把状态寄存器中的内容读入到CPU的某个寄存器中,通过测试寄存器中的不同位,来了解设备的状态。
传送必要的参数
命令寄存器
,用于存放处理机发来的各种控制命令
,以决定本次I/O 操作是接收数据还是发送数据等。方式寄存器
,用于控制本次传送数据的速率、发送的字符长度等
。如果是利用RS232C接口进行异步通信,在启动该接口之前,应先按通信规程设定下述参数: 波特率、奇偶校验方式、停止位数目及数据字节长度等
。
启动I/O设备
驱动程序传送相应的控制命令给控制器中的命令寄存器,从而启动I/O设备。
例子:对于字符设备,
-
若发出的是写命令,驱动程序便把一个字符(或字),传送给控制器;
-
若发出的是读命令,则驱动程序等待接收数据,并通过读入控制器的状态寄存器中状态字的方法来确定数据是否到达。
处理机与 I/O设备的并行
:在多道程序系统中,驱动程序【需要CPU参与控制:是运行在CPU上的软件,负责管理控制器的行为】 一旦发出I/O命令
,启动了一个I/O操作后
,驱动程序便把控制返回给 I/O 系统
,把自己阻塞起来
,直到中断到来时再被唤醒
。具体的 I/O 操作是在设备控制器【不需要CPU实时干预,一旦启动,可独立完成底层物理操作】的控制下进行的——在设备忙于传送数据时,处理机可以去干其它的事情。
6.4.3 对I/O设备的控制方式
1、使用轮询的可编程 I/O 方式 - 程序直接控制方式
轮询:在处理机向控制器发出一条I/O指令,启动输入设备输入数据时,要同时 把状态寄存器中的忙/闲标志 busy 置为1 ,然后 处理机不断地循环测试 busy
,直到busy=0为止将数据寄存器中的数据取出,送入内存指定单元中。接着再去启动读下一个数据,并置 busy=1。
状态寄存器中的忙/闲标志 busy:
当 busy=1 时
,表示输入机正在
将数据送入控制器的数据寄存器中但未结束,处理机应继续对该标志进行测试【设备处于忙状态
,处理机应继续持续监测busy
】。当 busy=0 时
,表明输入机已经
将输入数据送入控制器的数据寄存器中。【设备处于空闲状态
】处理机将数据寄存器中的数据取出,送入内存指定单元中。
缺点:
CPU 的绝大部分时间都处于等待 I/O 设备完成数据 I/O 的循环测试中,造成对 CPU的极大浪费。因为在 CPU 中无中断机构,使I/O设备无法向CPU报告它已完成了一个字符的输入操作。
2、使用中断的可编程 I/O 方式
工作流程 ⚙️(以输入为例)🖥️➡️📂
1️⃣ 进程发起 I/O 请求
- CPU 对 设备控制器 发出 I/O 命令(如读命令) 📄
- CPU 不等待,立即继续执行其他任务 ⏳ 【CPU 和 I/O 设备可以并行工作 🚀】
2️⃣ 设备控制器接管
- 控制 I/O 设备读取数据(比如键盘输入 ⌨️ 或磁盘读取 💾)
- 读完后,数据存入 数据寄存器 📊
3️⃣ 设备控制器发中断信号
- CPU 暂停当前工作,进入 中断处理模式 🛑
- 检查是否有错误 ❌➡️✅
4️⃣ CPU 取数据并写入内存
- 若无错,CPU 便向控制器发送取走数据的信号 📨
- 数据从 寄存器 通过 数据总线 🚌 写入 内存指定地址 🏢
5️⃣ CPU 恢复原任务
- 保存的现场恢复,继续执行之前任务 🏃♂️
3、直接存储器访问方式 - DMA
背景:中断驱动 I/O 的局限性 ❌
- 📌 以字节/字为单位传送(每次传输完都要中断 CPU)
- ⏳ 频繁中断导致高 CPU 开销(如 读 1KB 需要中断 1024 次!)
- 🐌 不适合块设备
DMA(Direct Memory Access)的引入 🎯
✅ 核心目标:进一步减少 CPU 对 I/O 的干预,让数据块直接和内存交互 🚀
📌 DMA 核心特点(对比中断驱动 I/O):
对比项 | 中断驱动 I/O | DMA (直接存储器访问) |
---|---|---|
数据传输单位 | 字节/字 🔢 | 块(如 1KB、4KB)📦 |
CPU 干预频率 | 每次传输都中断 ❗ | 仅开始和结束干预 ✅ |
数据流向 | 设备→CPU→内存 🚚 | 设备 直接→内存 🚀 |
适用场景 | 低速设备(键盘、鼠标)⌨️ | 高速块设备(磁盘、网卡)🖴🌐 |
DMA控制器的组成
DMA 控制器由三部分组成: 主机与DMA控制器的接口
;DMA 控制器与块设备的接口
;I/O 控制逻辑
。
用 4 个关键寄存器
实现 CPU 无干预的数据传输。
-
命令/状态寄存器(CR, Command/Status Register)
🎛️-
📌 作用:接收 CPU 的 I/O 命令,并反馈 设备状态。
-
✅ 功能:
-
CPU → DMAC:写入 读/写命令
-
DMAC → CPU:反馈 状态信息
-
-
-
内存地址寄存器(MAR, Memory Address Register)
🧠-
📌 作用:存储 数据在内存中的起始地址(读/写的目标地)。
-
✅ 功能:
-
输入(设备 → 内存):存放数据要写入内存的 目标地址
-
输出(内存 → 设备):存放数据从内存读取的 源地址
-
-
-
数据寄存器(DR, Data Register)
📦- 📌 作用:临时存放 正在传输的数据(中转站)。
- ✅ 功能:
- 输入模式:设备数据 → 先存入 DR → 再写入 内存(MAR 指定地址)
- 输出模式:内存数据 → 先存入 DR → 再传给 设备
-
数据计数器(DC, Data Counter)
🔢- 📌 作用:记录 存放本次CPU要读或写的字(节)数(每次传输后递减)。
- ✅ 功能:
- 初始化时:存放 总传输量
- 每次传输后:自动减 1(或按块递减)
- 归零时:触发 中断通知 CPU(“任务完成!”🎉)
工作过程
4、I/O 通道控制方式
DMA 的局限性
❌ 单块传输限制:每次 CPU 发送 1 条 I/O 指令,DMA 只能传输 1 个连续的数据块。
❌ 多块传输低效:如果数据要存储到 不同内存区域,需 CPU 多次干预(发多条 I/O 指令 + 处理多次中断)。
✅ I/O 通道(Channel)的主要功能
- 比 DMA 更智能:DMA 只能简单搬运数据块,而 I/O 通道 可以
执行 复杂的指令序列(通道程序)
。- 例如:
- 读取多个不连续数据块
- 写入不同内存区域
- 执行基本的校验、格式转换等操作
- 例如:
CPU 只需发 1 条启动指令
:CPU 告诉I/O 通道:要执行的通道程序的位置(首地址)+ 目标 I/O 设备并行性更强
:CPU、通道、I/O 设备 三者 并行工作,提高系统吞吐量。
方式 | 控制单位 | 任务复杂度 | CPU 干预 | 典型适用场景 |
---|---|---|---|---|
普通 DMA | 单块数据传输 | 仅搬运数据 | 每次 I/O 任务发 1 条指令 | 磁盘读/写单个文件块 |
I/O 通道 | 一组数据块 + 控制逻辑 | 可执行复杂操作 | 1 条指令启动整个任务序列 | 数据库查询、视频流处理 |
通道程序
🔹 通道控制的核心机制
通道
通过执行通道程序并与设备控制器协作完成I/O操作。
通道程序
= 一系列 通道指令(通道命令) 的集合,用于控制复杂的I/O任务。
🔍 通道指令的五个关键字段
字段 | 作用 | 示例说明 |
---|---|---|
操作码 | 指定I/O操作类型(读、写、控制等) | READ (从设备读数据)、WRITE (向设备写数据)、SEEK (移动磁盘磁头) |
内存地址 | 数据在内存中的起始地址(读操作存放目标,写操作来源) | 若操作码为READ ,表示数据存入内存的0x1000 地址处 |
计数 | 本次(读或者写)指令传输的字节数 | 计数=1024 → 本条指令传输1024字节的数据 |
结束位P | 标志通道程序是否结束 P=1表示最后一条指令 | P=1 → 执行完本条指令后,通道停止工作并通知CPU |
记录结束标志R | 标识数据记录的连续性 R=0→与下条指令属同一记录; R=1→当前指令是记录的最后部分) | R=1 → 本条指令处理的数据是一个逻辑记录(如文件块)的末尾,下一条指令属于新记录 |
完成一次读/写的过程 | CPU干预频率 | 每次I/O的数据传输单位 | 数据流向 | |
---|---|---|---|---|
程序直接控制方式 | CPU发出I/O命令后需要不断轮询 | 极高 | 字 | 设备→CPU→内存 内存→CPU→设备 |
中断驱动方式 | CPU发出I/O命令后可以做其他事, 本次I/O完成后 设备控制器向CPU发出中断信号 | 高 | 字 | 设备→CPU→内存 内存→CPU→设备 |
DMA方式 | CPU发出I/O命令后可以做其他事, 本次I/O完成后 DMA控制器向CPU发出中断信号 | 中 | 块 | 设备→内存 内存→设备 |
通道控制方式 | CPU发出I/O命令后可以做其他事。 通道会执行通道程序以完成I/O,完成后 通道向CPU发出中断信号 | 低 | 一组块 | 设备→内存 内存→设备 |
每一个阶段的优点都是解决了上一阶段的最大缺点。总体来说,整个发展过程就是要尽量减少CPU对I/O过程的干预,把CPU从繁杂的I/O控制事务中解脱出来,以便更多地去完成数据处理任务。
6.5 与设备无关的 I/O 软件
6.5.1 与设备无关(Device Independence)软件的基本概念
🔍1、 以物理设备名使用设备
✖ 问题描述及局限性
- 早期OS中,应用程序直接使用
物理设备名
请求I/O设备。 - 主要缺点:
设备分配僵化
:若请求的指定设备被占用
,即使物理设备名不同的同类设备空闲
,进程也会被阻塞
。兼容性差
:设备硬件升级后
(如旧打印机被替换),依赖具体物理名的程序将无法运行
。利用率低
:无法灵活分配同类设备中的空闲资源。
✨2、引入了逻辑设备名
引入目的:实现与设备的无关性。逻辑设备是抽象的设备名。用户程序通过逻辑名请求设备类别,OS动态分配具体物理设备。
例如/dev/printer,该设备名只是说明 用户需要使用打印机来打印输出,但并没有指定具体是哪一台打印机。
让程序按类型申请设备,系统自动分配空闲设备。只要还有同类设备可用,就不会阻塞;只有所请求的此类设备已全部分配完毕时才会因请求失败而阻塞。
【进行设备分配时,先查找该类设备中的第一台,如它已被分配,系统可立即去查找该类设备中第二台,若又被分配,系统接着去找第三台,若它尚未分配,便可将这台设备分配给进程。事实上,只要系统中有一台该类设备未被分配,进程就不会被阻塞。仅当所请求的此类设备已全部分配完毕时,进程才会因请求失败而阻塞。】
I/O 重定向,是指用于 I/O 操作的设备可以更换(即重定向),而不必改变应用程序。
🌰 示例:I/O重定向
- 场景:程序调试时输出到屏幕,正式运行时输出到打印机。
- 实现:修改逻辑设备表中
/dev/output
的映射(屏幕→打印机),无需修改程序。
🔄3、 逻辑设备名到物理设备名的转换
⚙ 转换机制:
逻辑设备表(LUT):
- 维护
逻辑名→物理设备驱动
的映射(类似内存管理中的页表)。 - 包含字段:
逻辑设备名
、物理设备名
、设备驱动程序入口
。
- 维护
转换过程:
- 进程通过逻辑名(如
/dev/printer
)发起I/O请求。 - OS查询逻辑设备表,分配当前可用的物理设备(如
printer2
)。 - 调用对应设备驱动完成操作。
- 进程通过逻辑名(如
6.5.2 与设备无关的软件
在与设备无关的软件中,包括了执行所有设备公有操作的软件:
-
设备驱动程序的统一接口
-
所有设备驱动程序与OS提供相同的接口
:-
新增设备驱动程序容易,减少适配成本。
-
方便开发人员对设备驱动程序的开发和维护。
-
-
用户使用
抽象的设备名,系统自动映射到具体驱动程序上
。 -
安全保护:
禁止用户直接访问硬件,防止越权操作
。
-
-
缓冲管理
-
背景:
CPU-I/O速度不匹配
——CPU速度远快于I/O设备(如硬盘、键盘),直接操作会导致CPU空等,利用率低。 -
解决方法:设置
缓冲区(Buffer)
作为数据中转站
,缓解速度矛盾
,提高系统效率。 -
常见缓冲区类型:
类型 描述 应用场景 单缓冲区
仅一个缓冲区,设备与CPU交替使用 简单设备(如鼠标) 双缓冲区
两个缓冲区交替工作(一个读/写,一个处理) 视频播放、实时数据采集 循环缓冲区
多个缓冲区构成环形队列,实现连续数据流 高吞吐设备(如网络卡) 公用缓冲池
动态分配缓冲区,按需供多个设备共享 多任务系统(如Linux/Windows)
-
-
差错控制
由于设备中有着许多的机械和电气部分,比主机更容易出现故障。错误可分为如下两类:
- ✅
暂时性错误(Transient Error)
- 原因:临时性异常(如电压波动、数据包丢失)
- 处理方式:通过**重试**自动恢复
- 示例:
- 网络传输:丢包时自动重传
- 磁盘读写:单次失败后重试多次(如10次),连续失败才报错
- ✅
持久性错误(Permanent Error)
- 原因:硬件物理损坏或不可逆故障(如磁盘划痕、电源故障)
- 处理方式:需 人工干预或系统级容错
- 示例:磁盘坏道:标记为坏块(Bad Block)并隔离
处理层级 责任范围 错误类型 设备驱动程序 处理暂时性错误(如重试、校验) 暂时性错误为主 设备独立性软件 处理驱动无法修复的错误(如坏块管理) 持久性错误 - ✅
-
对独立设备的分配与回收
设备类型 特点 示例 独占设备 同一时间只能被一个进程占用,需系统统一分配 打印机、扫描仪 共享设备 允许多个进程并发使用(通常无需显式分配) 磁盘、网络卡 -
独占设备的分配机制
-
分配条件
-
设备空闲
:检查目标设备是否未被占用
。 -
进程申请
:进程需主动发起请求
。
-
-
分配流程 : 进程请求 → OS检查设备状态 → 空闲则分配 / 忙则阻塞并加入队列
-
-
阻塞与唤醒机制
-
请求队列
:当设备被占用时,新请求的进程被放入设备的等待队列
(FIFO或优先级队列)。 -
唤醒条件:当前
持有设备的进程释放资源后
,OS从队列头部唤醒一个进程
。该进程获得设备并继续执行。
-
-
-
独立于设备的逻辑数据块
- 背景:
- 不同类型设备的数据交换单位、读取和传输速率是不相同,如字符型设备以单个字符(字)为单位,块设备是以一个数据块为单位。
- 即使同一类型设备(如不同品牌的磁盘),块大小可能不同
- 目标:
向高层
(如文件系统)提供统一的逻辑数据块
(Logical Block),隐藏底层设备的差异
。
- 背景:
6.5.3 设备分配
1、设备分配中的数据结构
设备控制表 DCT:用于记录设备的情况
控制器控制表COCT、通道控制表CHCT 和 系统设备表SDT
四张表关系
- 根据**
进程请求的物理设备名【后改进为逻辑设备名】
** → 查找SDT
SDT
→ 全局设备列表 → 指向DCT
(具体设备控制表)【若设备忙碌则将进程PCB挂到设备等待队列
中,不忙碌则将设备分配给进程。】DCT
→ 设备管理 → 指向COCT
(其所属的控制器)【若控制器忙碌则将进程PCB挂到控制器等待队列
中,不忙碌则将控制器分配给进程。】COCT
→ 控制器管理 → 指向CHCT
(连接的 I/O 通道)【若通道忙碌则将进程PCB挂到通道等待队列
中,不忙碌则将通道分配给进程。】
SDT -> DCT -> COCT -> CHCT
2、设备分配时应考虑的因素
设备的固有属性:
设备类型 | 特点 | 分配策略 | 典型示例 |
---|---|---|---|
独占设备 | 一次只能被一个进程占用,用完才能释放 | 静态分配:进程运行时独占,结束后释放 | 打印机、磁带机 |
共享设备 | 可被多个进程同时使用 | 动态分配 + 合理调度(如 FCFS、优先级) | 硬盘、网络接口 |
虚拟设备 | 通过SPOOLing技术模拟的共享设备 | 假脱机分配:将独占设备虚拟为共享设备,提高利用率 | 磁盘模拟打印机 |
设备分配算法:
-
先来先服务(FCFS - First Come First Serve)
-
核心思想
-
按照
进程请求设备的先后顺序
进行排队。 -
设备分配程序
优先分配资源给队首的进程
(最先发出请求的进程)。
-
-
实现方式
-
维护一个
设备请求队列(FIFO 队列)
。 -
当设备空闲时,
从队列头部取出一个进程进行分配
。
-
-
优缺点
优点 缺点 ✅ 简单易实现 ❌ 可能导致低优先级进程长时间等待(饥饿) ✅ 公平性高(按顺序来) ❌ I/O 密集型进程可能阻塞 CPU 密集型进程
-
-
优先级高者优先(Priority-Based Scheduling)
-
核心思想
-
进程的优先级
决定其获取设备的顺序。 -
优先级高的排在队列前面
,相同优先级的则按 FCFS 处理。
-
-
实现方式
-
设备请求队列按
优先级排序
(如高优先级→低优先级)。 -
当设备空闲时,
先检查最高优先级的进程
。
-
-
优缺点
优点 缺点 ✅ 关键任务优先执行(如系统进程) ❌ 低优先级任务可能无限等待 ✅ 适用于实时系统(紧急任务优先) ❌ 实现比 FCFS 复杂
-
设备分配中的安全性
分配方式 | 进程状态 | 死锁风险 | 特点 | 适用场景 |
---|---|---|---|---|
安全分配 | 进程发出 I/O 请求后立即阻塞,直到 I/O 完成 | ❌ 不会死锁 (不会保持任何资源,阻塞时不能申请新的资源) | 安全但低效 (CPU与I/O设备是串行工作的) | 简单的顺序 I/O 任务 |
不安全分配 | 进程可继续运行,仅在设备被占用时才阻塞 | ✅ 可能死锁(可能持有资源) | 高效但有风险 (需要死锁检测算法进行安全计算) | 高并发 I/O 环境 |
3、独占设备的分配程序
(1) 分配设备
-
查找设备控制表(DCT)
: 根据物理设备名【后改进为 逻辑设备名】
在系统设备表(SDT)
中查找对应的设备控制表(DCT)
。进程使用逻辑设备名申请 I/O,系统自动选择合适设备:
遍历该类设备的所有 DCT
。- 如果
所有设备都忙
,进程进入设备类等待队列
。 - 否则,找到
第一个空闲设备
,检测分配安全性
,并分配设备
。
- 如果
-
检查设备状态
- 设备忙?→ 进程挂入
设备等待队列
(阻塞)。 - 设备空闲?→ 检查分配是否安全(死锁检测)。
- 安全 → 分配设备
- 不安全 → 进程挂入设备队列(仍阻塞)。
- 设备忙?→ 进程挂入
(2) 分配控制器
从 DCT 查找控制器(COCT)
- 检查控制器是否繁忙
- 忙 → 进程挂入
控制器等待队列
。 - 空闲 → 分配控制器。
- 忙 → 进程挂入
(3) 分配通道
从 COCT 查找通道(CHCT)
- 检查通道是否空闲
- 忙 → 挂入
通道等待队列
。 - 空闲 → 分配通道。
- 忙 → 挂入
✅ 分配成功条件:设备 + 控制器 + 通道 均可用
,否则进程阻塞。
6.5.4 逻辑设备名到物理设备名映射的实现
逻辑设备表,用于将逻辑设备名映射为物理设备名。
1、逻辑设备表 LUT(Logical Unit Table)
表项:在逻辑设备表的每个表目中包含了三项 - 逻辑设备名
、物理设备名
和设备驱动程序的入口地址
。
流程:
首次分配
:- 当进程用逻辑设备名请求分配I/O设备时,
系统根据当时的具体情况
,为它分配一台相应的物理设备
。 - 同时在
逻辑设备表上建立一个表目
,填上应用程序中使用的逻辑设备名
和系统分配的物理设备名
,以及该设备驱动程序的入口地址
。
- 当进程用逻辑设备名请求分配I/O设备时,
后续分配
:- 当以后进程再利用该逻辑设备名请求 I/O操作时,系统
通过查找LUT
,便可找到
该逻辑设备所对应的物理设备
和该设备的驱动程序
。
- 当以后进程再利用该逻辑设备名请求 I/O操作时,系统
2、逻辑设备表的设置问题
在系统中可采取两种方式设置逻辑设备表:
- 第一种方式,
是在整个系统中只设置一张LUT
。由于系统中所有进程的设备分配情况都记录在同一张 LUT 中,因而不允许在 LUT 中具有相同的逻辑设备名
,这就要求所有用户都不使用相同的逻辑设备名。这种方式主要用于单用户系统中
。 - 第二种方式,
是为每个用户设置一张LUT
。每当用户登录时,系统便为该用户建立一个进程,同时也为之建立一张LUT
,并将该表放入进程的PCB中
。各个用户使用的逻辑设备名可以重复,适用于多用户操作系统。
6.6 用户层的 I/O 软件
6.6.1 系统调用与库函数
1、系统调用
定义
:系统调用是 用户态程序请求内核服务的唯一接口
,用于访问受保护的硬件资源和操作系统功能
。【 系统调用 作为中介,实现用户态到核心态的切换
,再由内核完成实际操作。】
系统调用是应用程序取得OS所有服务的唯一途径
。但是用户层的应用程序无法用一个统一的系统调用接口来完成所有类型设备的I/O,划分了不同接口——字符设备接口
、块设备接口
和 网络设备接口
过程
:
阻塞/非阻塞I/O
阻塞I/O
: 应用程序 发出I/O系统调用,进程需转为阻塞态等待,eg:字符设备接口–从键盘读一个字符get非阻塞I/O
: 应用程序 发出I/O系统调用,系统调用可迅速返回,进程无需阻塞等待。eg:块设备接口–往磁盘写数据write
2、库函数
定义
:库函数(Library Functions)是由 操作系统或编程语言提供
的一组 预编译函数
,封装了底层系统调用
,为开发者提供更高级、更便捷的操作接口。
预编译函数(Precompiled Functions)
是指在程序运行前
就已经被编译成二进制代码
并存储在库文件
(如.a
、.so
、.dll
) 中的函数。这些函数 可以被程序直接调用,无需在每次使用时重新编译。
库函数与系统调用的关系
:
- 许多库函数(如
read()
、write()
)直接封装系统调用(如sys_read
、sys_write
)。 - 部分库函数(如
printf()
或fopen()
)在系统调用的 基础上加入额外功能(缓冲、格式化等)。
不同操作系统下的库函数实现
系统/平台 | 库函数实现特点 |
---|---|
UNIX/Linux | 多数库函数与系统调用 一一对应。 |
Windows | 通过 Win32 API提供接口,不与底层系统调用直接对应。 |
6.6.2 假脱机(Spooling)系统
1、假脱机技术
SPOOLing 技术的背景
(1) 20世纪50年代的I/O瓶颈
-
核心矛盾:
CPU处理速度远快于低速I/O设备
(如磁带机、打印机)。 -
早期解决方案:
脱机输入/输出技术
(Off-line I/O):使用
专用外围控制机
,预先将数据 从慢速设备传输到高速磁盘【CPU直接从磁盘读写数据】 或 从高速磁盘传输到慢速设备。
(2) 多道程序技术的推动
- 多任务处理的引入使得
可用一道程序模拟脱机控制的逻辑
:- 输入进程:将低速输入设备数据 → 磁盘(模拟脱机输入)。
- 输出进程:将磁盘数据 → 低速输出设备(模拟脱机输出)。
- 关键改进:在
联机(On-line)
状态下用软件的方式模拟脱机技术
,无需额外硬件控制机
。
SPOOLing 技术的核心思想
SPOOLing(Simultaneous Peripheral Operations Online,假脱机技术)是一种在 联机环境
下模拟脱机输入/输出的技术
。
- “假脱机” = “假装脱机”(实际是联机操作)。
- 用磁盘作为缓冲区,实现CPU计算和I/O操作的并行执行。
对比项 | 脱机技术(Off-line) | SPOOLing(假脱机) |
---|---|---|
硬件依赖 | 需要专用外围控制机 | 完全由软件实现,无需额外硬件 |
运行时状态 | 物理脱离主机操作 | 联机操作(主机直接控制) |
并行性 | 需手动切换设备 | CPU与I/O设备真正并行工作 |
现代应用 | 已被淘汰 | 仍广泛使用(如打印队列、批处理系统) |
2、SPOOLing 的组成
SPOOLing系统建立在通道技术
和多道程序技术
的基础上,以高速随机外存(通常为磁盘)为后援存储器。
SPOOLing 的四大核心组件由 “两井、两区、两进程、一管理程序” 构成:
- 输入井与输出井
- 物理位置:
磁盘
上开辟的专用存储区域
(以文件形式
组织,称为井文件
)。 - 功能:
输入井
:模拟脱机输入,缓存从输入设备(如键盘、扫描仪)采集的原始数据。输出井
:模拟脱机输出,缓存CPU处理后的结果数据(如待打印文件)。
- 数据管理:
一个文件仅存放某一个进程的
输入(或者输出)数据所有进程的数据
输入(或输出)文件链接成
为一个输入(或输出)队列
。
- 物理位置:
- 输入缓冲区与输出缓冲区
- 物理位置:
内存
中开辟的高速缓冲区域
。 - 功能:
输入缓冲区
:临时存储从输入设备→输入井
传输的数据,解决设备与磁盘的速度 mismatch。输出缓冲区
:临时存储从输出井→输出设备
传输的数据,解决磁盘与设备的速度 mismatch。
- 意义:磁盘虽快于I/O设备,但仍慢于CPU。内存缓冲区进一步减少CPU等待时间(类似快递中转站)。
- 物理位置:
- 输入进程和输出进程
- 功能:
输入进程也称为预输入进程
:用于模拟脱机输入时的外围控制机
,将用户要求的数据从输入设备传送到输入缓冲区,再存放到输入开。CPU直接从输入井读入内存。输出进程也称为缓输出进程
:用于模拟脱机输出时的外围控制机
,把用户要求输入的数据从内存传送并存放到输出井,待输出设备空闲时,再将输出井中的数据经过输出缓冲区输出至输出设备上。
- 注意:两进程均
后台运行
,对用户透明。
- 功能:
- 井管理程序
- 角色:SPOOLing系统的“调度中心”。
- 功能:
输入控制
:当CPU请求输入数据时,从输入井读取→返回给CPU
。输出控制
:当CPU生成输出数据时,从CPU→写入输出井
。资源协调
:管理井文件的访问权限与队列优先级。
- 调用时机:由操作系统在发出I/O请求时触发
3、SPOOLing 系统的特点
⚡ 提高 I/O 速度(解决速度不匹配问题)
-
背景:
-
低速 I/O 设备与高速 CPU/磁盘存在速度差异
。 -
直接 I/O操作会导致 CPU 频繁等待,效率低下。
-
-
✅SPOOLing 的解决方式
- 🎯从
对低速设备的直接 I/O 变成 对高速磁盘的存取
(类似“预加载”)。 - 🎯
CPU 可以并行计算
,不用等待 I/O 完成
(异步 I/O)。 - 🎯减少CPU 等待时间,提高系统吞吐量。
- 🎯从
-
🌰例子:打印文件时,数据先快速写入磁盘,然后SPOOLing 系统按打印机速度慢慢输出,避免 CPU 等待。
⚡ 将独占设备改造为共享设备
-
背景:
-
独占设备同一时刻只能被一个进程占用
。 -
若多个进程同时请求打印,必须串行执行,导致效率低下。
-
-
✅ SPOOLing 的解决方式
-
🎯
不再直接分配设备
,而是:- 用户进程的
打印请求先存入磁盘输出井
(每个进程单独占用一块空间)。 操作系统动态调度
,按照 FCFS(先来先服务)或优先级规则,从输出井取数据送给打印机
。
- 用户进程的
-
🎯优势:
多个进程可以“同时”提交打印任务
(实际上是写入磁盘,而非真实打印)。- 打印机
看起来是“共享”的
,但实际物理打印机仍是一次打印一个任务。
-
-
例子:🌰
-
多人在线打印:
- 用户A打印文件 → 数据存入输出井A区。
- 用户B打印文件 → 数据存入输出井B区。
SPOOLing 系统按顺序取数据打印,用户感知不到等待(以为“同时”打印)。
-
⚡ 实现虚拟设备功能
-
核心思想
-
SPOOLing
通过磁盘缓冲区模拟多个逻辑设备
,即使物理设备只有一个
。 -
每个进程认为自己“独占”设备,但实际上
所有任务通过磁盘队列管理
。
-
-
✅虚拟化实现:
-
🎯
输入虚拟化
:多个进程可以“同时”从SPOOLing 输入井读取数据
。- 即使物理输入设备只有一个,由于数据缓存在磁盘,多个进程可以轮流读取。
-
🎯
输出虚拟化
:多个进程可以“同时”写入输出井
。- 即使物理输入设备只有一个,SPOOLing 系统负责排队输出,用户无感知。
-
4、假脱机打印机系统
组成:
磁盘缓冲区
。在磁盘上
开辟的一个存储空间,用于暂存用户程序的输出数据
,在该缓冲区中可以设置几个盘块队列,如空盘块队列、满盘块队列等。打印缓冲区
。用于缓和 CPU 和磁盘之间速度不匹配的矛盾,设置在内存中
,暂存从磁盘缓冲区送来的数据
,以后再传送给打印设备进行打印
。假脱机管理进程
和假脱机打印进程
。由假脱机管理进程
为每个要求打印的用户数据建立一个假脱机文件
,并把它放入假脱机文件队列
中,由假脱机打印进程
依次对队列中的文件进行打印
。
📝 假脱机打印系统(SPOOLing)工作流程详解
1️⃣ 用户请求打印时的处理
🔹 🚫 不直接分配打印机
,而是由 假脱机管理进程
完成以下两步:
- 📂
申请磁盘缓冲空间
:- 在
输出井(磁盘缓冲区) 分配一个空闲盘块
。 - 将
用户要打印的数据 存入该盘块 (暂存)
。
- 在
- 📋
创建打印请求表
:填写用户打印要求
(如文件名、格式)。- 将该表
挂接到假脱机打印队列
。
✅ 用户感知:用户进程认为“打印已完成” 🎉,但实际上 只是数据存入磁盘,并未真正打印!
2️⃣ 实际打印过程(由假脱机打印进程负责)
🔹 打印机空闲时
,系统执行以下操作:
- 📜
取队首打印请求表
:- 从
假脱机文件队列的队首摘取一张请求打印表
。
- 从
- 💾
数据从磁盘 → 内存 → 打印机
:- 把
磁盘缓冲区
搬运到打印缓冲区
。 由打印机真正输出
(慢速 I/O)。
- 把
- 🔄
循环处理打印队列
:- 如果
队列非空,继续处理下一个任务
。 队列为空时,假脱机进程休眠
⏸️,直到有新任务到来才 被唤醒 🔔。
- 如果
5、守护进程(daemon) - 改进版
📌 改进点
取消假脱机管理进程
,改为守护进程(唯一有权操作打印机)
- 守护进程 :为用户
在磁盘缓冲区中申请一个空闲盘块
,并将要打印的数据送入其中
,将该盘块的首址返回给请求进程
- 用户(请求)进程:
生成文件
【包含打印要求和指向装有打印输出数据盘块的指针等信息】+文件放入假脱机文件队列(目录)
- 守护进程
逐个处理队列中的请求
⚙️ 工作流程
-
守护进程
:- ⚡
申请空闲磁盘块
,存入打印数据
→返回磁盘块首地址
- ⚡
-
用户(请求)进程
:- ⚡
获取磁盘块首地址
- 📂
生成打印请求文件
(包含打印参数 +守护进程返回的磁盘块地址) - 📤
放入假脱机文件队列
- ⚡
-
守护进程
:- 🔍
检查队列
:- 有任务 → 从队首取出请求文件
- 无任务 → 睡眠💤(等待唤醒)
- 🖨️
执行打印
:- 根据请求文件找到数据地址 → 读取磁盘数据
- 打印 → 完成后删除请求文件
- 🔄 循环处理直至队列空
- 🔍
6.7 缓冲区管理
6.7.1 缓冲的引入
引入缓冲区的原因:
-
缓和CPU与I/O设备间速度不匹配的矛盾
。事实上,凡在数据到达速率与其离去速率不同的地方,都可设置缓冲区,以缓和它们之间速率不匹配的矛盾。
-
减少对CPU 的中断频率,放宽对 CPU 中断响应时间的限制
。
-
解决数据粒度不匹配的问题
。解决在生产者和消费者之间交换的
数据粒度(数据单元大小)
不匹配的问题。生产者粒度 < 消费者粒度
(如生产者每次传1KB,消费者需要4KB)- ✅解法:生产者连续写入多个小数据块,
攒够1个消费单元
后,消费者一次性取出处理
- ✅解法:生产者连续写入多个小数据块,
生产者粒度 > 消费者粒度
(如生产者每次传4KB,消费者需要1KB)- ✅解法:生产者写入大数据块后,消费者
分多次取出部分数据
处理
- ✅解法:生产者写入大数据块后,消费者
-
提高 CPU 和 I/O 设备之间的并行性。
📌 核心作用:解耦生产者(CPU)和消费者(I/O 设备)的直接依赖,实现并行操作 ➡️ 提高吞吐率。
🌰 示例:CPU 与打印机
- 无缓冲:CPU 必须等待打印机完成当前任务才能发送下一批数据 ❌ 串行,效率低。
- 有缓冲:
- CPU 快速写入缓冲区后立即处理其他任务 ⚡
- 打印机 从缓冲区逐步取出数据打印 🖨
- 结果:CPU 计算与 I/O 输出并行执行 ✅
6.7.2 单缓冲区和双缓冲区
1. 无缓冲区的限制
- 问题:
- 生产者必须等待消费者就绪才能传递数据,否则阻塞。
- 消费者也需等待生产者,否则空转。
- 缺点:强耦合,效率低,可能造成资源闲置。
2. 引入缓冲区后的优化
- 作用:
- 生产者不必等待,可直接写入缓冲区。
- 消费者按需读取,避免阻塞生产者。
- 优势:
- 解耦生产与消费,支持并行执行。
- 平衡速度差异(生产者快 vs 消费者慢)。
1、单缓冲区(Single Buffer)
基本概念
- 单缓冲区结构:操作系统为
每个
用户进程发出的I/O 请求
在内存
分配一个临时缓冲区
。 - 适用场景:块设备(如磁盘)和字符设备(如终端输入)的 数据缓冲。
块设备(如磁盘)的 I/O 流程
(若题目中没有特别说明,一个缓冲区的大小就是一个块)
📌 注意事项:
- 当
缓冲区数据非空时
,不能往缓冲区冲入数据
,只能先从缓冲区把数据传出; - 当缓冲区为空时可以往缓冲区冲入数据,但
必须把缓冲区充满以后
,才能从缓冲区把数据传出
。
📌 关键参数:
T
:磁盘 读入缓冲区
的时间M
:缓冲区传送到用户区
的时间C
:CPU 处理数据
的时间
📌 执行流程:
数据输入阶段(T)
和CPU 处理阶段(C)
可并行
(重叠执行)。- 总处理时间:
- 若 T > C →
T + M
- 若 C > T →
C + M
- 统一公式:
Max(C, T) + M
- 若 T > C →
🔹 效率影响:优化点:尽量让 T 和 C 重叠,减少总耗时。
字符设备(如键盘输入)的 I/O 流程
📌 输入(读操作):缓冲区 暂存 一行字符数据
,输入时 用户进程挂起(阻塞)
等待数据就绪。
📌 输出(写操作):
- 用户进程
写入一行数据到缓冲区
,由操作系统处理。 - 问题:若
前一行数据未被处理完
,但用户进程又写入新数据,则进程阻塞
(需等待缓冲区可用)。
🔹 特点:串行操作
,依赖 缓冲区清空才能继续 I/O
。
总结对比
设备类型 | 并行性 | 关键特点 |
---|---|---|
块设备(磁盘) | ✅ CPU 计算 & I/O 可并行 | 时间模型:Max(C, T) + M |
字符设备(键盘) | ❌ 串行操作 | 单行缓冲,进程可能因缓冲区未空而阻塞 |
2、双缓冲区(Double Buffer)
基本概念
- 双缓冲区机制:系统维护
两个缓冲区
(Buffer 1 & Buffer 2),交替使用
。 - 核心优势:
提升并行性
:I/O 设备 和 CPU 可同时操作不同的缓冲区
。减少等待时间
:I/O 设备和CPU 彼此不依赖对方完成,双方互不等待
。
块设备(如磁盘)I/O 优化
-
📌
执行流程
:-
Buffer 1 接收数据(T 时间)(I/O 设备写入)。
-
Buffer 1 满后,设备 切换至 Buffer 2 继续写入(T 时间)。
-
同时,CPU 从 Buffer 1 读取数据并处理(M + C 时间)。
-
-
📌
总处理时间分析
:-
理想情况下(完全并行,去除了 M 的影响):
Max(C, T)
【计算时间(C)
和I/O 时间(T)
】-
If
C < T
:I/O 连续输入(无 CPU 阻塞)。C < T (I/O 是瓶颈,CPU 快于 I/O)
CPU 处理一块数据的速度(C) 比 I/O 传输一块数据的速度(T)快。
🔍 特点
- I/O 时间(T) > 计算时间(C) → 系统
瓶颈在 I/O 设备
(磁盘/网络等)。 - I/O 设备持续输入(不因 CPU 计算快而被迫等待)。
📌 运行流程(例子:T=4s,C=2s)
时间(s) Buffer 1 Buffer 2 CPU 状态 0–4 写入数据(I/O,4s) 空闲 等待数据 4–6 CPU 处理 Buffer 1(2s) 开始写入 Buffer 2(4s) 计算 Buffer 1 6–8 空闲(可再写入) Buffer 2 写入中 CPU 空闲(Buffer 2 未满) 8–10 重新写入 Buffer 1(4s) CPU 处理 Buffer 2(2s) 计算 Buffer 2 10–12 Buffer 1 写入中 空闲 CPU 空闲(Buffer 1 未满) 🚀 观察与分析
CPU 会短暂等待(6–8s、10–12s)
:- 因为
CPU 处理更快(C=2s)
,但I/O 尚未写完下一个 Buffer(T=4s)
,所以CPU 会有空闲区间
。 - 但
I/O 设备始终不停
(Buffer 1 & Buffer 2 交替写入)。
- 因为
I/O 持续输入
:平均每 T=4s 完成一个数据块的写入(不因 CPU 计算而减慢)。- 对比单缓冲(更优)
- 单缓冲(无双缓冲):CPU 处理 2s 后必须等 I/O 4s →
6s 处理一块数据
。 - 双缓冲:虽然 CPU 偶尔等待,但 I/O 设备一直全速运行→
4s 处理一块数据
。
- 单缓冲(无双缓冲):CPU 处理 2s 后必须等 I/O 4s →
🎯 结论(C < T)
✅
I/O 连续输入
(设备不空闲)。
✅CPU 利用率较低
(因其太快),但 比单缓冲高效(I/O 不会被 CPU 阻塞)。 - I/O 时间(T) > 计算时间(C) → 系统
-
If
C > T
:CPU 不需等待 I/O(数据始终可用)。C > T(CPU 是瓶颈,计算慢于 I/O)
CPU 处理一块数据的速度(C) 比 I/O 传输一块数据的速度(T)慢。
🔍 特点
- 计算时间(C) > I/O 时间(T) → 系统
瓶颈在 CPU
。 CPU 永远有数据可用
(不因 I/O 慢而等待)。
📌 运行流程(例子:T=2s, C=4s)
时间(s) Buffer 1 Buffer 2 CPU 状态 0–2 写入数据(I/O,2s) 空闲 等待数据 2–6 CPU 计算 Buffer 1(4s) 写入 Buffer 2(2s) → 2–4s 写满 计算 Buffer 1 4–6 CPU 仍计算 Buffer 1 Buffer 2 已满,待 CPU 处理 CPU 仍在计算Buffer 1 6–10 重新写入 Buffer 1(2s) CPU 计算 Buffer 2(4s) 计算 Buffer 2 8–10 Buffer 1 已满(8s) CPU 仍在算 Buffer 2 CPU 仍在计算Buffer 2 🚀 观察与分析
CPU 不需等待
:- 在 2–6s,CPU 计算 Buffer 1 的同时,I/O 已写满 Buffer 2(4s 时 Buffer 2 可用)。
- 6s 时,CPU 立即能切换到 Buffer 2(因早已写满)。
I/O 设备偶尔空闲
:- 4–6s:I/O 设备 无事可做(
因 Buffer 1 & Buffer 2 均被占用
)。 - 6s 后,I/O 开始填充 Buffer 1,但 CPU 计算较慢(C=4s),因此 I/O 利用率较低。
- 4–6s:I/O 设备 无事可做(
- 对比单缓冲(更优)
- 单缓冲:CPU 算 4s + I/O 写 2s →
6s 处理一块数据
。 - 双缓冲:CPU 全速计算,永不等待 →
4s 处理一块数据
。
- 单缓冲:CPU 算 4s + I/O 写 2s →
🎯 结论(C > T)
✅
CPU 不需等待 I/O
(数据始终提前准备好)。
✅I/O 利用率较低
(因其太快,CPU 算不完)。 - 计算时间(C) > I/O 时间(T) → 系统
-
-
字符设备(如键盘输入)优化
-
📌 行输入模式(交互式场景):
-
用户输入第一行到 Buffer 1
(I/O 占用 Buffer 1)。 -
CPU 处理 Buffer 1
,用户同时输入第二行到 Buffer 2
。
-
-
🔹 解决单缓冲问题:
-
单缓冲
:用户输入需等待上一行处理完毕
→ 阻塞。 -
双缓冲
:输入 & 计算完全并行
,无等待时间。
-
3、单缓冲与双缓冲在双向通信中的作用
1. 单缓冲的问题(单向通信限制)
- 配置:两台机器(A 和 B)
各使用一个缓冲区
。 - 限制:
任意时刻只能 单向传输
(A → B 或 B → A)。无法同时收发
,因为单缓冲的读写是冲突的(同一缓冲区不能同时被写入和读取)。
- 类比:🚪 单行通道,同一时间只允许一个人通过。
2. 双缓冲的解决方案(双向全双工通信)
- 配置:每台机器各设置
两个缓冲区
——发送缓冲区(Tx)和接收缓冲区(Rx)
。 - 优势:
- A 的发送缓冲区 → B 的接收缓冲区(A → B)。
- B 的发送缓冲区 → A 的接收缓冲区(B → A)。
同时进行,互不干扰
,实现真正的全双工通信
。
- 类比:🛣️ 双向车道,两辆车可以同时反向行驶。
3. 总结对比
方案 | 缓冲配置 | 通信能力 | 效率 |
---|---|---|---|
单缓冲 | 每台机器 1 个缓冲区 | 半双工(单向交替传输) | 低,易阻塞 |
双缓冲 | 发送 + 接收缓冲区各 1 | 全双工(同时双向传输) | 高,无冲突 |
6.7.3 环形/循环缓冲区
1、环形缓冲区的组成
- 多个缓冲区。在环形缓冲中包括多个缓冲区,其
每个缓冲区的大小相同
。作为输入的多缓冲区可分为三种类型
:用于装输入数据的空缓冲区R
、已装满数据的缓冲区G
以及计算进程正在使用的现行工作缓冲区C
- 多个指针。作为
输入的缓冲区可设置三个指针
: 用于指示计算进程下一个可用缓冲区 G的指针 Nextg
、指示输入进程下次可用的空缓冲区R的指针 Nexti
,以及用于指示计算进程正在使用的缓冲区C的指针Current
。
2、环形缓冲区的使用
🔹 Getbuf 过程:分配缓冲区给进程使用。
计算进程调用
:- 获取
Nextg 指向的 G缓冲区
(含数据)。 Current 指针
指向该缓冲区的起始地址
(开始处理)。Nextg 移向下一个 G缓冲区
(轮询)。
- 获取
输入进程调用
:- 获取
Nexti 指向的 R缓冲区
(空)。 - 装入数据后,
Nexti 移向下一个 R缓冲区
。
- 获取
🔹==Releasebuf 过程==:释放缓冲区并更新状态。
计算进程调用(处理完数据后)
:- 将当前
C缓冲区(已消费)标记为空(R缓冲区)
。【C → R】
- 将当前
输入进程调用(填充完数据后)
:- 将当前
R缓冲区(已填充)标记为待计算(G缓冲区)
。【R → G】
- 将当前
3、进程之间的同步问题
环形缓冲区的并行执行机制
- 输入进程和计算进程通过环形缓冲区并行工作:
- Nexti(输入指针):按顺时针移动,指向下一个 待填充的空缓冲区(R)。
- Nextg(计算指针):按顺时针移动,指向下一个 待处理的满缓冲区(G)。
- 理想情况:两个指针
保持一定间隔
,避免竞争,实现高效并发。
针追赶的两种情况
🔹 情况1:Nexti 追上 Nextg(输入进程太快)
- 现象:所有缓冲区 被填满(
无空 R 缓冲区
)。 - 原因:
输入速度 > 计算速度
。 - 解决:
输入进程阻塞
,等待计算进程处理数据。计算进程释放
, 使之成为空缓冲区R
(调用Releasebuf
)后,唤醒输入线程
。
- 术语:
系统受计算限制
(CPU 是瓶颈)。
🔹 情况2:Nextg 追上 Nexti(计算进程太快)
- 现象:所有缓冲区 被抽空(
无满 G 缓冲区
)。 - 原因:
计算速度 > 输入速度
。 - 解决:
计算进程阻塞
,等待输入进程填充数据。输入进程释放满缓冲区
(调用Releasebuf
)后,唤醒计算线程
。
- 术语:
系统受 I/O 限制
(输入设备是瓶颈)。
6.7.4 缓冲池(Buffer Pool)
1. 专用缓冲区的缺点
- 问题:每个生产/消费组独占缓冲区,导致:
- 内存浪费(大量独立缓冲)
- 利用率低(空闲时无法共享)
2. 缓冲池的优化
- 设计:
- 公用缓冲池:多个进程共享一组缓冲区(输入/输出通用)。
- 管理机制:通过数据结构+操作函数动态分配/回收缓冲。
- 优势:
- 内存高效(减少冗余分配)
- 灵活复用(按需分配,避免闲置)
3. 关键区别
特性 专用缓冲区 缓冲池 管理方式 静态独占 动态共享 内存开销 高(固定分配) 低(按需分配) 适用场景 简单小系统 复杂高并发系统
1、缓冲池的组成
缓冲区的组成
缓冲首部
(管理信息
)- 缓冲区号、设备号、数据块号
- 同步信号量(控制并发访问)
- 队列链接指针(用于链接同类缓冲)
缓冲体
(存放实际数据
)
缓冲池的三种队列
队列类型 | 说明 | 指针 |
---|---|---|
空白缓冲队列 (emq) | 所有空闲缓冲区 组成的链表 | F(emq) → 队首,L(emq) → 队尾 |
输入队列 (inq) | 已装满输入数据 的缓冲区链表 | F(inq) 、L(inq) |
输出队列 (outq) | 已装满输出数据 的缓冲区链表 | F(outq) 、L(outq) |
四种工作缓冲区
收容输入数据的工作缓冲区
提取输入数据的工作缓冲区
收容输出数据的工作缓冲区
提取输出数据的工作缓冲区
2、Getbuf 过程和 Putbuf 过程
信号量设计
信号量 | 作用 |
---|---|
MS(type) | 互斥信号量,确保同一时间只有一个进程访问队列(如 inq /outq /emq )。 |
RS(type) | 资源信号量,表示队列中可用缓冲区的数量(同步生产/消费的速度)。 |
(1) Getbuf(type)
—— 从队列获取缓冲区
void Getbuf(unsigned type) { Wait(RS(type)); // 检查资源可用性(阻塞若无缓冲) Wait(MS(type)); // 申请队列互斥访问权 B(number) = Takebuf(type); // 取出缓冲区 Signal(MS(type)); // 释放队列锁
}
- 顺序关键:先检查资源(
RS
)再加锁(MS
),否则可能死锁。
(2) Putbuf(type, number)
—— 将缓冲区放回队列
void Putbuf(unsigned type, int number) { Wait(MS(type)); // 申请队列互斥访问权 Addbuf(type, number); // 将缓冲区加入队列 Signal(MS(type)); // 释放队列锁 Signal(RS(type)); // 增加可用资源计数
}
互斥性:
MS(type)
保护队列操作原子性(如Takebuf
/Addbuf
)。同步性:
RS(type)
控制缓冲区数量,避免:
- 生产者过快:无空缓冲时阻塞(
Wait(RS)
)。- 消费者过快:无数据时阻塞(依赖输入/输出队列的
RS
)。
3、缓冲区的工作方式
收容输入(外设→内存):输入进程请求输入数据
操作者:输入进程
(如磁盘读取)
步骤:
获取空缓冲
:hin = Getbuf(emq)
- 从空白队列
emq
取一个空缓冲区hin
。
- 从空白队列
填充数据
:将外设数据写入hin
。挂到输入队列
:Putbuf(inq, hin)
- 将装满数据的
hin
加入输入队列inq
,等待计算进程处理。
- 将装满数据的
信号量变化:
emq
的RS
减1(空缓冲减少)。inq
的RS
加1(输入数据增加)。
提取输入(内存→计算):计算进程想要取得一块输入数据
操作者:计算进程
(如CPU处理)
步骤:
获取输入缓冲
:sin = Getbuf(inq)
- 从输入队列
inq
取一个装满数据的缓冲区sin
。
- 从输入队列
处理数据
:计算进程读取sin
中的数据。归还空缓冲
:Putbuf(emq, sin)
- 将处理完的
sin
放回空白队列emq
,供其他进程复用。
- 将处理完的
信号量变化:
inq
的RS
减1(输入数据减少)。emq
的RS
加1(空缓冲增加)。
收容输出(计算→内存):计算进程想要将准备好的数据冲入缓冲区
操作者:计算进程
步骤:
获取空缓冲
:hout = Getbuf(emq)
- 从
emq
取一个空缓冲区hout
。
- 从
填充输出数据
:将计算结果写入hout
。挂到输出队列
:Putbuf(outq, hout)
- 将装满输出数据的
hout
加入输出队列outq
,等待输出进程。
- 将装满输出数据的
信号量变化:
emq
的RS
减1(空缓冲减少)。outq
的RS
加1(输出数据增加)。
提取输出(内存→外设):输出进程请求输出数据
操作者:输出进程
(如写入磁盘)
步骤:
获取输出缓冲
:sout = Getbuf(outq)
- 从
outq
取一个装满输出数据的缓冲区sout
。
- 从
输出数据
:将sout
中的数据写入外设。归还空缓冲
:Putbuf(emq, sout)
- 将清空的
sout
放回emq
,完成资源回收。
- 将清空的
信号量变化:
outq
的RS
减1(输出数据减少)。emq
的RS
加1(空缓冲增加)。
6.8 磁盘存储器的性能和调度
6.8.1 磁盘性能简述
1、数据的组织和格式
物理结构 💽
- 磁盘设备由一个或多个
物理盘片
组成。 - 每个盘片有
1~2个存储面(Surface)
(双面盘片两面均可存储数据)。
磁道与存储密度 🎯
- 每个盘面划分为多个同心圆状的
磁道(Track)
,磁道间留有 间隙(Gap)。 磁盘密度
:每英寸中所存储的位数- 存储规则:
每条磁道存储相同数量的二进制位
(位密度恒定)。 - 密度差异:
内层磁道
比外层磁道
密度更高
(因为周长更小,但存储相同位数)。
扇区与盘块 🍕
- 每条磁道逻辑划分为多个
扇区(Sector)
:- 软盘:8~32个扇区。
- 硬盘:可达数百个扇区。
扇区 = 盘块(数据块)
:是磁盘最小读写单位。- 扇区之间也保留间隙(Gap),用于控制与同步。
柱面:所有盘面中相对位置相同的磁道组成柱面
可用
(柱面号,盘面号,扇区号)
来定位任意一个“磁盘块”。读取一个“块”:
- ①根据
“柱面号”移动磁臂
,让磁头指向指定柱面;- ②根据
盘面号
,激活
指定盘面对应的磁头
;- ③磁盘旋转的过程中,
指定的扇区会从磁头下面划过
,这样就完成了对指定扇区的读/写。
物理记录与存储容量 📦
- 物理记录(块):一个扇区存储一个物理记录,磁盘总容量由三要素决定:
扇区数
(每磁道)磁道数
(每盘面)磁盘面数
(双面盘片 × 盘片数)
传统设计的局限性 ⚠️
- 旧方案:所有磁道扇区数相同(恒定位密度),导致
外层磁道空间浪费
(周长更长但存储量相同)。
现代优化:多环带设计 🔄
环带(Zoned Bit Recording)
:- 将盘面划分为多个同心环带,
同一环带内所有磁道扇区数相同
。 外层环带扇区数 > 内层环带
(匹配实际物理容量)。- 优势:显著提升存储密度,容量可增加20%~50%。
- 将盘面划分为多个同心环带,
磁盘格式化
1️⃣ 低级格式化(物理格式化) - 划分扇区
:
温盘(温切斯特盘)
中一条磁道格式化的情况。其中每条磁道(Track)含有30个固定大小的扇区(Sectors)
,每个扇区容量为600个字节
,其中512个字节存放数据
,其余的用于存放控制信息
。每个扇区包括两个字段:
①
标识符字段(ID Field)
,
- 其中一个字节的
SYNCH
具有特定的位图像,作为该字段的定界符
,- 利用磁道号(
Track
)、磁头号(Head#
)及扇区号(Sectors #
)三者来标识一个扇区
;CRC
字段用于段校验
。②
数据字段(Data Field)
,存放 512个字节的数据
。间距(Gap): 1~多个字节的空隙,区分不同扇区/字段,便于磁头寻址
2️⃣ 分区(Partitioning)- 每个分区由若干柱面组成
- 目的:将磁盘划分为多个
逻辑独立的存储区域
(如C盘、D盘)。 - 核心结构:
0 号扇区
(主引导记录 MBR):存储分区表
(记录各分区的起始扇区、大小
)。- 活动分区:标记为可引导(含操作系统启动代码)。
3️⃣ 高级格式化(逻辑格式化)- 创建文件系统
-
作用:将
分区
转换为操作系统可识别的文件系统
,使其能存储和管理文件。 -
关键操作:
-
设置
一个引导块
自举程序
: 是计算机开机时第一个运行的小程序,它检查硬件是否正常
并加载操作系统的核心部分从而唤醒操作系统
引导块
:完整的自举程序放
在磁盘的启动块(即引导块/启动分区)上,启动块位于磁盘的固定位置
。开机过程: 计算机运行ROM中的“自举装入程序”,找到引导块 --> 将引导块的“自举程序”读入内存 --> 初始化
拥有启动分区的磁盘称为
启动磁盘
或系统磁盘(C:盘)
-
创建
文件系统的根目录
-
初始化
存储空间管理所用的数据结构
- 位示图
- 空闲分区表
-
坏块管理
:- 坏块:无法正常使用的扇区
简单磁盘
:(建立文件系统时)对整个磁盘进行坏块检查,标明哪些扇区是坏扇区, -在FAT表上标明
。(坏块对操作系统不透明
)复杂磁盘
:磁盘控制器
(磁盘设备内部的一个硬件部件)会维护一个坏块链表
。扇区备用
:会保留一些“备用扇区”,用于替换坏块
。(坏块对操作系统透明
)
-
2、磁盘的类型
磁盘的主要分类
- 存储介质
- 硬盘(HDD/SSD)
- 软盘(Floppy Disk)
- 盘片数量
- 单片盘
- 多片盘
- 磁头工作方式
- 固定头磁盘
- 移动头磁盘
- 根据盘片是否可更换
- 固定盘磁盘
- 可换盘磁盘
⚙️ 固定头 vs 移动头磁盘的核心区别
对比项 | 固定头磁盘 | 移动头磁盘 |
---|---|---|
磁头数量 | 每个磁道一个磁头(如1000磁道=1000磁头) | 每个盘面一个磁头(如双面盘=2个磁头) |
寻道方式 | 无需移动,磁头固定 | 磁头需移动寻道(机械延迟) |
读写性能 | 并行读写,速度快(适用于高吞吐场景) | 串行读写,速度慢(受限于磁头移动时间) |
成本 | 高昂(磁头数量多) | 低廉(结构简单) |
典型应用 | 主要用于大容量磁盘上 | 用于中小型磁盘设备中 |
3、磁盘访问时间
📝 1、寻道时间(Ts):磁头从当前位置移动到目标磁道所需的时间,属于机械延迟。
计算公式
T s = m × n + s T_s = m × n + s Ts=m×n+s
m
:每跨越一个磁道耗时,与磁盘驱动器速度相关的常数
(单位:ms/磁道)。- 普通磁盘:m ≈ 0.2
- 高速磁盘:m ≤ 0.1
n
:需要跨越的磁道数量
(如从磁道10移动到磁道50,则n=40)【跨越磁道越多,时间越长】。s
:磁臂启动时间
(固定开销,约 2ms)。
📝 2、旋转延迟时间(Tᵣ):磁头到达目标磁道后,等待目标扇区旋转到磁头下方所需的时间。
-
✅ 属于机械延迟,与磁盘转速(RPM)直接相关。
-
🔄 平均旋转延迟 ≈ 磁盘旋转半圈的时间。
A v e r a g e T r = 1 2 × 单圈旋转时间 = 1 2 × 1 r r :转速,单位 转 / 秒 或 转 / 分 Average \quad T_r = \frac{1}{2} × 单圈旋转时间 = \frac{1}{2} × \frac{1}{r}\\ r:转速,单位 \quad 转/秒 \quad 或 \quad 转/分 AverageTr=21×单圈旋转时间=21×r1r:转速,单位转/秒或转/分软盘为300 r/min 到 600r/min,硬盘一般为 7200 r/min 到 15 000 r/min
🔹 7200 RPM 硬盘 - 【一分钟7200圈,求单圈旋转时间1/7200】
T r = 1 m i n 7200 r / m i n = 60000 m s 7200 r / m i n ≈ 8.3 m s A v e r a g e T r = 8.3 m s 2 ≈ 4.15 m s T_r = \frac{1min}{7200 r/min} = \frac{60000 ms}{7200 r/min} ≈ 8.3ms \\ Average \quad T_r = \frac{8.3ms}{2} ≈ 4.15ms Tr=7200r/min1min=7200r/min60000ms≈8.3msAverageTr=28.3ms≈4.15ms
🔹 15,000 RPM 硬盘
T r = 1 m i n 15000 r / m i n = 60000 m s 15000 r / m i n = 4 m s A v e r a g e T r = 4 m s 2 = 2 m s T_r = \frac{1min}{15000 r/min} = \frac{60000 ms}{15000 r/min} = 4ms \\ Average \quad T_r = \frac{4ms}{2} = 2ms Tr=15000r/min1min=15000r/min60000ms=4msAverageTr=24ms=2ms
🔹 300 RPM 软盘
T r = 1 m i n 300 r / m i n = 60000 m s 300 r / m i n = 200 m s A v e r a g e T r = 200 m s 2 = 100 m s T_r = \frac{1min}{300 r/min} = \frac{60000 ms}{300 r/min} = 200ms \\ Average \quad T_r = \frac{200ms}{2} = 100ms Tr=300r/min1min=300r/min60000ms=200msAverageTr=2200ms=100ms
减少延迟时间
1、
交替编号
2、
错位命名
📝 3、传输时间Tt。指把数据从磁盘读出或向磁盘写入数据所经历的时间。
T t = 1 r ∗ b N = b r N r :磁盘每秒钟的转的圈数 b :每次所读 / 写的字节数 N :一条磁道上的字节数 T_t = \frac{1}{r} * \frac{b}{N}= \frac{b}{rN}\\\ r:磁盘每秒钟的转的圈数\\ b:每次所读/写的字节数 \\ N:一条磁道上的字节数 Tt=r1∗Nb=rNb r:磁盘每秒钟的转的圈数b:每次所读/写的字节数N:一条磁道上的字节数
磁盘访问时间:
T a = T s + T r + T t = T s + 1 2 r + b r N T_a = T_s + T_r + T_t = T_s + \frac{1}{2r} + \frac{b}{rN} Ta=Ts+Tr+Tt=Ts+2r1+rNb
6.8.2 早期的磁盘调度算法
1、先来先服务(FCFS)
根据进程请求访问磁盘的先后顺序进行调度
✅ 优点
- 公平性📌:严格按照请求到达的顺序处理,不偏袒任何进程。
- 集中请求时表现尚可🎯:如果请求的磁道集中在相邻区域,寻道时间不会太长。
❌ 缺点
磁道分散时性能差🐌:当请求的磁道分布范围广(如进程随机访问不同位置),磁头会频繁来回移动,导致平均寻道时间(Ts)激增。
2、最短寻道时间优先(SSTF)
会优先处理的磁道是与当前磁头最近的磁道。可以保证每次的寻道时间最短,但是并不能保证总的寻道时间最短。
✅ 优点:性能较好,平均寻道时间短
❌ 缺点:可能产生“饥饿”现象【原因在于:磁头在一个小区域内来回来去地移动】
6.8.3 基于扫描的磁盘调度算法
1、扫描(SCAN)/电梯算法
解决SSTF 算法会产生饥饿的问题
处理的磁道是与当前磁头最近的磁道,但是只有磁头移动到最外侧磁道的时候才能往内移动,移动到最内侧磁道的时候才能往外移动。
✅ 优点:性能较好,平均寻道时间较短,不会产生饥饿现象
❌ 缺点:
- 只有到达最边上的磁道时才能改变磁头移动方向,事实上,处理了184号磁道的访问请求之后就不需要再往右移动磁头了,造成了
空跑
。 - SCAN算法
对于各个位置磁道的响应频率不平均
(如:假设此时磁头正在往右移动,且刚处理过90号磁道,那么下次处理90号磁道的请求就需要等磁头从200往左移动很长一段距离;而响应了184号磁道的请求之后,很快又可以再次响应184号磁道的请求了【184离200近】)
2、LOOK调度算法
解决SCAN算法会产生 空跑 的问题
如果在磁头移动方向上已经没有别的请求,就可以立即改变磁头移动方向。(边移动边观察,因此叫 LOOK)
✅ 优点:比起SCAN 算法来,不需要每次都移动到最外侧或最内侧才改变磁头方向,使寻道时间进一步缩短
3、循环扫描(CSCAN)算法
解决SCAN算法对于各个位置磁道的响应频率不平均的问题
规定只有磁头朝某个特定方向移动时才处理磁道访问请求,而返回时直接快速移动至起始端而不处理任何请求。
✅ 优点:比起SCAN 来,对于各个位置磁道的响应频率很平均。
❌ 缺点:
- 只有到达最边上的磁道时才能改变磁头移动方向,事实上,处理了184号磁道的访问请求之后就不需要再往右移动磁头了,造成了
空跑
。 - 比起SCAN算法来,平均寻道时间更长。
4、CLOOK 调度算法
解决CSCAN算法会产生 空跑 的问题
如果磁头移动的方向上已经没有磁道访问请求了,就可以立即让磁头返回,并且磁头只需要返回到有磁道访问请求的位置即可。
✅ 优点:比起C-SCAN 算法来,不需要每次都移动到最外侧或最内侧才改变磁头方向,使寻道时间进一步缩短
5、NStepSCAN 和 FSCAN 调度算法
NStepSCAN算法
🔍 核心思想:
-
分组处理请求 📚
- 将磁盘请求队列
分割成多个子队列
(每个队列长度为N
)。 - 按
FCFS顺序
处理这些子队列
,但每个子队列内部用SCAN算法
调度。
- 将磁盘请求队列
-
动态防垄断 🛡️
新请求
被放入新的子队列
,不会干扰当前正在处理的队列。- 避免单个进程因高频访问同一磁道而垄断磁臂(即“磁臂粘着”)。
磁臂粘着:有一个或几个进程反复请求对某一磁道的 I/O 操作,从而垄断了整个磁盘设备。
-
平衡性能⚖️
N较大时
:接近SCAN算法性能(高效寻道)。N=1时
:退化为FCFS(绝对公平,但性能差)。中间值N
:折中方案,适合多数场景。
FSCAN 调度算法
算法实质上是N步SCAN算法的简化,即FSCAN只将磁盘请求队列分成两个子队列
,双队列轮流处理 🔄
活动队列
:当前待处理的磁盘IO请求,按SCAN算法调度(像电梯一样来回扫)。等待队列
:扫描过程中新到达的请求,暂时不处理,攒到下一次扫描。
6.8.4 固态硬盘SSD
原理:基于闪存技术Flash Memory属于电可擦除ROM,即EEPROM
结构
闪存翻译层
:负责翻译逻辑块号,找到对应页(Page)
存储介质
: 多个闪存芯片
(Flash Chip) – 每个芯片包含多个块
(block) – 每个块包含多个页
(page)
💥 读写性能特性
-
以页(page)为单位读/写
- 相当于磁盘的“扇区" -
以块(block)为单位“擦除”
,擦干净的块,其中的每页都可以写一次,读无限次 -
支持随机访问,系统给定一个逻辑地址,闪存翻译层可通过电路迅速定位到对应的物理地址
-
读快、写慢
。要写的页如果有数据,则不能写入,需要将块内其他页全部复制到一个新的(擦除过的)块中,再在新的块对应的页写入数据。闪存翻译层将映射改为这个新块的地址。
💥 与机械硬盘对比
SSD读写速度快
,随机访问性能高
,用电路控制访问位置
;机械硬盘
通过移动磁臂旋转磁盘控制访问位置
,有寻道时间和旋转延迟SSD 安静无噪音
、耐摔抗震
、能耗低
、造价更贵
SSD的一个"块"被擦除次数过多
(重复写同一个块)可能会坏
掉,而机械硬盘的扇区不会因为写的次数太多而坏掉
💥 磨损均衡技术
- 思想: 将
“擦除"平均分布在各个块
上,以提升使用寿命 动态磨损均衡
:写入数据时,优先选择累计擦除次数少
的新闪存块静态磨损均衡
:SSD监测
并自动进行数据分配、迁移
,让老旧的闪存块
承担以读为主
的储存任务,让较新的闪存块
承担更多的写任务
例题
参考:
教材:
计算机操作系统(第四版) (汤小丹) (Z-Library).pdf
视频:
王道计算机考研 操作系统