系列目录
- 持续更新~
- 欢迎评论区留言指正
- 如果你是Obsidian用户,可以导入自己的笔记库中,效果最佳
- ⚠️如需转载,请标明出处!
第1章 计算机系统概述
1.1 操作系统的基本概念
1.1_1 操作系统的定义、功能
- OS的定义(概念)
- 负责管理协调硬件、软件等计算机资源的工作
- 为上层用户、应用程序提供简单易用的服务
- 是一种系统软件(最接近硬件的一层软件)
- 功能和目标
- 资源的管理者
- 处理机管理
- 存储器管理
- 文件管理
- 设备管理
- 向上层提供服务
- 给普通用户的
- GUI 用户图形界面
- 命令接口
- 联机命令接口
- 脱机命令接口
- 给软件/程序员用的
- 程序接口——即系统调用
- 给普通用户的
- 对硬件机器的拓展
- 扩充机器
- 资源的管理者
1.1_2 操作系统的特征
- 操作系统的特征
并发和共享是OS的最基本的两个特征f- 并发
- 共享
- 互斥共享方式(如对摄像头设备的共享使用)
- 同时共享方式(如对硬盘资源的共享使用)
- 虚拟
- 空分复用技术(如虚拟存储技术)
- 时分复用技术(如虚拟处理器技术)
- 异步
1.2 操作系统的发展与分类
- OS的发展与分类
后面三个不是重点- 手工操作阶段——缺点:人机速度矛盾
- 批处理阶段
- 单道批处理系统(引入脱机输入输出技术)
- 优点:缓解人机速度矛盾
- 缺点:资源利用率依然很低
- 多道批处理系统(OS开始出现)
- 优点:多道程序并发执行,资源利用率高
- 缺点:不提供人机交互功能
- 单道批处理系统(引入脱机输入输出技术)
- 分时OS
- 优点:提供人机交互功能
- 缺点:不能优先处理紧急任务
- 实时OS
- 硬实时系统——必须在绝对严格的规定时间内完成处理
- 软实时系统——能接受偶尔违反时间规定
- 优点:能优先处理紧急任务
- 网络OS
- 分布式OS
- 个人计算机OS
1.3 操作系统的运行环境🌟
1.3_1 操作系统的运行机制🌟
- 简单了解程序的运行原理
- 高级语言编写代码——>机器指令
- 程序运行的过程就是CPU执行指令的过程
- 两类程序
- 内核程序
- 用户程序
- 两类指令
- 特权指令
- 非特权指令
- 两种处理器状态
- 内核态/核心态/管态——可执行除访管指令外的所有指令
- 用户态/目态——只能执行非特权指令
- 内核
- 内核(Kernel)是OS最重要最核心的部分
- 由很多内核程序组成OS内核
- 🌟如何变态?
- 内核态——>用户态:一条修改PSW的特权指令
- 用户态——>内核态:由中断引起,硬件自动完成(硬件中断程序)
1.3_2 中断和异常
- 中断的作用
- 让OS内核强行夺回CPU的控制权
- 使CPU从用户态变为内核态
- 中断的分类
- 内中断(又称异常、例外)
- 陷阱、陷入(trap)
- 故障(fault)
- 终止(abort)
- 外中断(又称“中断”,狭义上的)
- 时钟中断
- I/O中断请求
- 内中断(又称异常、例外)
- 中断机制的基本实现原理
- 检查中断信号
- 内中断:CPU在执行指令时会检查是否有异常发生
- 外中断:每个指令周期末尾,CPU都会检查是否有外中断信号需要处理
- 找到相应的中断处理程序
- 通过“中断向量表”实现
- 检查中断信号
1.3_3 系统调用
- 系统调用
- 定义:操作系统对应用程序/程序员提供的接口
- 系统调用与库函数的区别
- 有的库函数对系统调用的进一步封装
- 有的库函数没有使用系统调用
- (按功能)分类
凡是与共享资源有关的操作,都需要通过系统调用来实现- 设备管理
- 文件管理
- 进程控制
- 进程通信
- 内存管理
- 系统调用的过程
- 传参
- 陷入指令/Trap/访管
- 由OS内核程序处理系统调用请求
- 返回应用程序
1.4 操作系统结构
- 操作系统体系结构
- 大内核(宏内核/单内核)——Linux、UNIX
将OS的主要功能模块都作为系统内核,运行在核心态,通常也采用了“模块化”的思想- 优点:性能高,内核内部各种功能都可以直接相互调用
- 缺点:
- 内核庞大功能复杂,难以维护
- 大内核中某个功能模块出错,就可能导致整个系统崩溃
- 微内核——Windows NT
只把中断、原语、进程通信等最核心的功能放入内核,进程管理、文件管理、设备管理等功能以用户进程的形式运行在用户态- 优点:
- 内核小功能少、易于维护,内核可靠性高
- 内核外的某个功能模块出错不会导致整个系统崩溃
- 缺点:
- 性能低,需要频繁地在核心态/用户态之间切换
- 用户态下的各功能模块不可直接相互调用,只能通过内核的“消息传递”间接通信
- 优点:
- 分层结构
内核分多层,每层可单向调用(相邻)更低一层提供的接口- 优点:
- 便于调试和验证,自底向上逐层调试验证
- 易扩充和易维护,各层之间调用接口清晰固定
- 缺点:
- 仅可调用相邻低层,难以合理定义各层的边界
- 效率低,不可跨层调用,系统调用执行时间长
- 优点:
- 模块化
将内核划分为多个模块,各模块之间相互协作- 优点
- 模块间逻辑清晰易于维护,确定模块间接口后即可多模块同时开发
- 支持动态加载新的内核模块(如:安装设备驱动程序、安装新的文件系统模块到内核),增强OS适应性
- 任何模块都可以直接调用其他模块,无需采用消息传递进行通信,效率高
- 缺点:
- 模块间的接口定义未必合理、实用
- 模块间相互依赖,更难调试和验证
- 优点
- 外核(exokernel)
内核负责进程调度、进程通信等功能,外核负责为用户进程分配未经抽象的硬件资源,且由外核负责保证资源使用安全- 优点:
- 外核可直接给用户进程分配“不虚拟、不抽象”的硬件资源,使用户进程可以更灵活的使用硬件资源
- 减少了虚拟硬件资源的“映射层”,提升效率
- 缺点:
- 降低了系统的一致性
- 使系统变得更复杂
- 优点:
- 大内核(宏内核/单内核)——Linux、UNIX
1.5 操作系统引导
- 操作系统引导(Boot)过程
- CPU从一个特定主存地址开始,取指令,执行ROM中的引导程序(先进行硬件自检,再开机)
- 将磁盘的第一块——主引导记录PCB 读入内存,执行磁盘引导程序,扫描分区表
- 从活动分区(又称主分区,即安装了OS的分区)读入分区引导记录PBR,执行其中的程序
- 从根目录下找到完整的OS初始化程序(即 启动管理器)并执行,完成“开机”的一系列动作
举例: - CPU加电激活后,会从最顶端的主存地址FFFF0H获得一条JMP指令(该地址仅有16字节,放不下一段程序),以跳到更低地址去执行BIOS程序(BIOS程序在内存最开始的空间构建中断向量表和相应服务程序,以实现后续POST过程中要用到中断调用等功能)
- ==然后进行通电自检POST(Power-on Self Test)以检测硬件是否有故障
- 完成POST后,BIOS需要在硬盘、光驱或软驱等存储设备搜寻OS内核的位置以启动OS(在硬盘逻辑格式化之前,需要先对硬盘进行分区,即创建硬盘分区表。分区完成后,对物理分区进行逻辑格式化,即创建文件系统,为每个分区初始化一个特定的文件系统,并创建文件系统的根目录;另外,如果某个分区采用Unix文件系统,还要在该分区中建立文件系统的索引结点表)
第2章 进程与线程
2.1 进程与线程
2.1.1 进程的概念、组成、特征
- 概念
程序:静态的,存在在磁盘里的可执行文件,也就是一系列的指令集合
进程(Process):是动态的,使程序的一次执行过程,同一个成许多次执行会对应多个进程,如:多开qq - 组成
一个程序开始运行前,需要创建对应的进程,也就需要创建相应的PCB
进程是进程实体的运行过程,使系统进行资源分配和调度的一个独立单位
进程实体(进程映像)的组成- PCB
PCB,Process Control Block,一种数据结构,是进程存在的唯一标志
当进程被创建时,OS会为其创建PCB;当进程结束时,会回收其PCB
OS(进程的管理者)所需的数据都在PCB中- 进程描述信息
- 进程标识符PID
- 用户标识符UID
- 进程控制和管理信息
- CPU、磁盘、网络流量使用情况统计
- 进程当前状态:就绪态/阻塞态/运行态
- 资源分配清单
- 正在使用哪些文件
- 正在使用哪些内存区域
- 正在使用哪些I/O设备
- 处理机相关信息
- 如PSW、PC等等各种寄存器的值(用于实现进程切换)
- 进程描述信息
- 程序段
- 包含程序的代码(指令序列)
- 数据段
- 包含运行过程中产生的各种数据(如:程序中定义的变量)
- PCB
- 特征
- 动态性
- 动态性是进程最基本的特征
- 进程是程序的一次执行过程,是动态地产生、变化和消亡的
- 并发性
- 内存中有多个进程实体,各进程可并发执行
- 独立性
- 进程时能独立运行、独立获得资源、独立接受调度的基本单位
- 异步性
- 各进程按各自独立的、不可预知的速度向前推进,OS要提供“进程同步机制”来解决异步问题
- 结构性
- 每个进程都会配置一个PCB。结构上看,进程由程序段、数据段、PCB组成
- 动态性
2.1.2 进程的状态与转换、进程的组织
-
状态
- 运行态:CPU✅其他所需资源❌
- 就绪态:CPU❌其他所需资源✅(CPU很忙)
- 阻塞态:CPU❌其他所需资源❌
- 创建态:OS为新进程分配资源、创建PCB
- 终止态:OS回收进程的资源、撤销PCB
-
进程状态间的转换
- 就绪态—>运行态:进程被调度
- 运行态—>就绪态:时间片到,或CPU被其他高优先级的进程抢占
- 运行态—>阻塞态:等待系统资源分配,或等待某事件发生(主动行为)
- 阻塞态—>就绪态:资源分配到位,等待的事件发生(被动行为)
- 创建态—>就绪态:系统完成创建进程相关的工作
- 运行态—>终止态:进程运行结束,或运行过程中遇到不可修复的错误
2.1.3 进程控制
- 基本概念
- 进程控制——实现进程状态的转换
- 进程控制用原语实现
- 原语用关/开中断来实现
- 原语是一种特殊的程序
- 原语的执行必须一气呵成,不可中断(原子性)
- 相关控制原语
进程控制原语必做三件事:
1、更新PCB中的信息
2、将PCB插入合适的队列
3、分配/回收资源- 进程的创建
- 进程的终止
- 进程的阻塞
- 进程的唤醒(阻塞与唤醒要成对出现)
- 进程的切换
2.1.4 进程通信
- 共享存储
- 设置一个共享内存区域,并映射到进程的虚拟地址空间
- 要互斥地访问共享空间(由通信进程自己负责实现互斥)
- 两种方式
- 基于数据结构的共享(低级)——灵活性差、速度慢
- 基于存储区的共享(高级)—— 灵活性高、速度快
- 消息传递
- 传递结构化的消息(消息头/消息体)
- 系统提供“发送/接收原语”
- 两种方式
- 直接通信方式:消息直接挂到接收进程的消息队列里
- 间接(信箱)通信方式:消息先发到中间体(信箱)
- 管道通信
- 设置一个特殊的共享文件(管道),其实就是一个内存缓冲区,而其本质又是一个循环队列
- 一个管道只能实现半双工通信
- 实现双向同时通信要建立两个管道
- 各进程要互斥访问管道(由OS负责实现互斥)
- 管道写满时,写进程阻塞,管道读空时,读进程阻塞
2.1.5 线程的概念
- 线程的属性
- 线程是处理机调度的单位
- 多CPU计算机中,各个线程可占用不同的CPU
- 每个线程都有一个线程ID、线程控制块(TCB)
- 线程也有就绪、阻塞、运行三种基本状态
- 线程几乎不拥有系统资源
- 同一进程的不同线程间共享进程的资源
- 由于共享内存地址空间,同一进程中的线程间通信甚至无需系统干预
- 同一进程中的线程切换,不会引起进程切换
- 不同进程中的线程切换,会引起进程切换
- 切换同进程内的线程,系统开销很小
- 切换进程,系统开销很大
2.1.6 线程的实现方式和多线程模型
- 线程的实现方式
- 用户级线程(ULT, User-Level Thread):从用户视角能看到的线程,由线程库实现
- 内核级线程(KLT, kernel-Level Thread):从OS视角看到的线程,由OS实现(内核级线程才是处理机分配的单位)
- 组合方式:用户级/内核级线程的结合
- 多线程模型
- 一对一模型
一个用户级线程映射到一个内核级线程- 优:各个线程可分配到多核处理机并行执行,并发度高
- 缺:线程管理都需要OS支持,开销大
- 多对一模型
多个用户级线程映射到一个内核级线程- 优:线程管理开销小效率高
- 缺:一个线程阻塞会导致整个进程都被阻塞(并发度低)
- 多对多模型
n个用户级线程映射到m个内核级线程(n≥m)- 集二者之所长
- 一对一模型
2.1.7 线程的状态与转换
-
线程的状态与转换
-
线程的组织与控制
2.2 处理机调度
2.2.1 调度的概念、层次
- 处理机调度
按某种算法选择一个进程将处理机分配给它- 作业:一个具体的任务
用户向系统提交一个作业≈用户让OS启动一个程序(来处理一个具体的任务) - 三个层次
- 作业调度(高级调度)
按照某种规则,从后备队列中选择合适的作业将此调入内存,并为其创建进程 - 内存调度(中级调度)
按照某种规则,从挂起队列中选择合适的进程将其数据调回内存 - 进程调度(低级调度)
按照某种规则,从就绪队列中选择一个进程为其分配处理机
- 作业调度(高级调度)
- 三层调度的联系、对比
越高级的调度发生频率越低- 高级调度(作业调度)
- 外存——>内存(面向作业)
- 发生频率:最低
- 变态: 无——>创建态——>就绪态
- 中级调度(内存调度)
- 外存——>内存(面向进程)
- 发生频率:中等
- 变态:挂起态——>就绪态(阻塞挂起——>阻塞态)
- 低级调度(进程调度)
- 内存——>CPU
- 发生频率:最高
- 变态:就绪态——>运行态
- 高级调度(作业调度)
- 补充知识
- 为减轻系统负载,提高资源利用率,暂时不执行的进程会被调用到外存从而变为“挂起态”
- (自命题)七状态模型:在五状态模型基础上加入“就绪挂起”和“阻塞挂起”两种状态
挂起态(suspend)细分为:就绪挂起和阻塞挂起
- 作业:一个具体的任务
2.2.2 进程调度的时机、切换与过程、方式
- 进程调度的时机
- 需要进程调度的时机
- 主动放弃
- 进程正常终止
- 运行过程中发生异常而终止
- 主动阻塞(如 等待I/O)
- 被动放弃
- 分给进程的时间片用完
- 有更紧急的事情需要处理(如 I/O中断)
- 有更高优先级的进程进入就绪队列
- 主动放弃
- 不能进程调度的时机
- 在处理中断的过程中
- 进程在OS内核程序临界区中
- 原子操作过程中(原语)
- 需要进程调度的时机
- 进程调度的切换与过程
- 狭义的“调度”和“切换”的区别
- 切换过程
- 对原来运行进程各种数据的保存
- 对新的进程各种数据的恢复
- 重要结论:进程调度、切换是有代价的,并不是调度越频繁,并发度就越高
- 方式
- 非剥夺调度方式(非抢占式)
只能由当前运行的进程主动放弃CPU - 剥夺调度方式(抢占式)
可由OS剥夺当前进程的CPU使用权
- 非剥夺调度方式(非抢占式)
2.2.3 调度器和闲逛进程
-
调度器/调度程序(scheduler)
OS内核的一个重要的程序模块
-
闲逛进程(idle)
调度程序永远的备胎,没有其他就绪进程时,运行闲逛进程
特性:- 优先级最低
- 可能是0地址指令,占一个完整的指令周期(指令周期末尾例行检查中断)
- 能耗低
2.2.4 调度算法的评价指标
- CPU利用率
利用率 = 忙碌的时间 总时间 利用率=\frac{忙碌的时间}{总时间} 利用率=总时间忙碌的时间 - 系统吞吐量
系统吞吐量 = 总完成作业数 所花时间 系统吞吐量=\frac{总完成作业数}{所花时间} 系统吞吐量=所花时间总完成作业数 - 周转时间
周转时间 = 完成时间 − 到达时间 ( 提交时间 ) 周转时间=完成时间-到达时间(提交时间) 周转时间=完成时间−到达时间(提交时间) - 平均周转时间
平均周转时间 = 周转时间 运行时间 平均周转时间=\frac{周转时间}{运行时间} 平均周转时间=运行时间周转时间 - 等待时间
等待时间 = 周转时间 − 运行时间 等待时间=周转时间-运行时间 等待时间=周转时间−运行时间 - 响应时间
从用户提交请求到首次产生响应所用的时间
2.2.5 调度算法
- 典型调度算法分类
-
早期批处理系统(非交互式系统)
- 先来先服务(调度算法)FCFS
- 短作业优先SJF
- 非抢占式
- 短作业优先SJF
- 短进程优先SPF
- 抢占式
- 最短剩余时间优先SRTN
- 非抢占式
- 高响应比优先HRRN
-
交互式系统
- 时间片轮转RR
- 优先级
- 多级反馈队列
- 多级队列
-
2.3 同步与互斥
2.3.1 进程同步、进程互斥
- 进程同步
- 并发性带来了异步性,有时需要通过进程同步解决这种异步问题
- 有的进程之间需要相互配合地完成工作,各进程的工作推进需要遵循一定的先后顺序
- 进程互斥
==临界资源:一次仅允许一个进程使用的资源- 对临界资源的访问,需要互斥的进行,即同一时间段内只能允许一个进程访问该资源
- 四个部分(临界资源的访问分为)
- 进入区
检查是否进入临界区,若可进入,需要“上锁” - 临界区(临界段)
进程中访问临界资源的那段代码 - 退出区
负责“解锁” - 剩余区
其余代码部分
- 进入区
- (进程互斥)需要遵循的原则
- 空闲让进
临界区空闲时,应允许一个进程访问 - 忙则等待
临界区正在被访问时,其他试图访问的进程需要等待 - 有限等待
要在有限时间内进入临界区,保证不会饥饿 - 让权等待
进不了临界区的进程,要释放处理机,防止忙等
- 空闲让进
2.3.2 进程互斥的软件实现方法🌟
- 进程互斥的软件实现方法
turn表“谦让”和flag表“意愿”的思想- 单标志法
公用整型变量turn表“谦让”- 在进入区只做“检查”,不“上锁”
- 在退出区把临界区的使用权转交给另一个进程(相当于在退出区既给另一进程“解锁”,又给自己“上锁”)
- 主要问题:不遵循“空闲让进”原则
- 双标志先检查
flag数组(想要进入临界区)表“意愿”
“检查”和“上锁”并不能一气呵成- 在进入区先“检查”后“上锁”,退出区“解锁”
- 主要问题:不遵循“忙则等待”原则
- 双标志后检查
- 在进入区先“加锁”后“检查”,退出区“解锁”
- 主要问题:不遵循“空闲让进、有限等待”原则,可能导致“饥饿”
- Peterson算法
单标志法和双标志后检查法的结合- 在进入区“主动争取—主动谦让—检查对方是否想进、己方是否谦让”
- 主要问题:不遵循“让权等待”原则,会发生CPU“忙等”
- 单标志法
2.3.3 进程互斥的硬件实现方法🌟
- 进程互斥的硬件实现方法
- 中断屏蔽方法
关中断指令只对关中断的特定处理机有用
不适合多处理机系统- 使用“开/关中断”指令实现
- 优点:简单高效
- 缺点:只适用于单处理机;只适用于OS内核进程
- TestAndSet/TestAndSetLock(TS指令/TSL指令)
- old记录是否已被上锁;
- 再将lock设为true;
- 检查临界区是否已被上锁(若已上锁,则循环重复前几步)
- 优点:实现简单;适用于多处理机环境
- 缺点:不满足“让权等待”——可能会出现忙等现象
- Swap指令(XCHG指令)
逻辑上同TSL
- 中断屏蔽方法
2.3.4 互斥锁
2.3.5 信号量机制🌟🌟
- 整型信号量
- 用一个整数型变量作为信号量,数值表示某种资源数
- 整型信号量与普通型变量的区别:对信号量只能执行 初始化、P、V三种操作
- 整型信号量存在的问题:不满足让“权等待”原则
- 记录型信号量🌟🌟🌟
大题、小题超高频考点——几乎每年必考大题- S.value 表示某种资源数,S.L指向等待该资源的队列
- P 操作中,一定是先S.value–,之后可能需要执行 block 原语——资源不够,主动阻塞
- V 操作中,一定是先S.value++,之后可能执行 wakeup 原语——唤醒一个阻塞进程
- 可用记录型信号量实现系统资源的“申请”和“释放”
- 可以用记录型信号量实现进程互斥、进程同步
- ⚠️:学会自己推断什么条件下需要执行 block 或 wakeup
2.3.6 用信号量实现进程互斥、同步、前驱关系
- 实现进程互斥
- 分析问题,确定临界区
- 设置互斥信号量,初值为1
- 临界区之前对信号量执行P操作
- 临界区之后对信号量执行V操作
- 实现进程同步
前V后P- 分析问题,找出哪里需要实现“一前一后”的同步关系
- 设置同步信号量,初始值为0
- 在“前操作”之后执行V操作
- 在“后操作”之前执行P操作
- 实现进程的前驱关系
本质上是多级同步问题- 分析问题,画出前驱图,把每一对前驱关系都看成一个同步问题
- 为每一对前去关系设置同步信号量,初值为0
- 在每个“前操作”之后执行V操作
- 在每个“后操作”之前执行P操作
2.3.7 生产者-消费者问题
先V后P
2.3.8 多生产者-多消费者问题
2.3.9 吸烟者问题
2.3.10 读者写者问题
遇到进程同步问题应参考生产者-消费者问题;而进程互斥问题应参考读者写者问题
2.3.11 哲学家进餐问题
遇到一个进程需要同时持有多个临界资源的情况这种问题,应参考哲学家问题
2.3.12 管程
解决信号量机制编程麻烦、易出错的问题
类比“类(class)”的概念
- 组成
- 共享数据结构
- 对数据结构初始化的语句
- 一组用来访问数据结构的过程(函数)
- 基本特征
- 各外部进程/线程只能通过管程提供的特定“入口”才能访问共享数据结构
- 每次仅允许一个进程在管程内执行某个内部过程
- 补充
- 各进程必须互斥访问管程的特性是由编译器实现的
- 可在管程中设置条件变量及等待/唤醒操作wait()/signal()以解决同步问题
2.4 死锁
2.4.1 死锁的概念
定义:各进程相互等待对方手里的资源,导致各进程都阻塞,无法向前推进
对不可剥夺资源的不合理分配,有可能导致死锁
- 死锁、饥饿、死循环的区别
- 死锁:至少是两个进程一起死锁,死锁进程处于阻塞态
- 饥饿:可以只有一个进程饥饿,饥饿进程可能阻塞也可能就绪
- 死循环:可能只有一个进程发生死循环,死循环的进程可上处理机(可执行)
- 死锁和饥饿由OS解决,而死循环由程序员解决
- 死锁产生的必要条件
- 互斥条件
对必须互斥使用的资源的争抢才会导致死锁 - 不剥夺条件
进程保持的资源只能主动释放,不可强行剥夺 - 请求和保持条件
保持着某些资源不放的同时,请求别的资源 - 循环等待条件
- 存在一种资源的循环等待链
- 循环等待不一定死锁,死锁一定有循环等待链
- 互斥条件
- 死锁的处理策略
- 预防死锁(静态策略)
不允许死锁发生- 破坏互斥条件
- 破坏不剥夺条件
- 破坏请求和保持条件
- 破坏循环等待条件
- 避免死锁(动态策略)
不允许死锁发生
死锁系统进入不安全状态(银行家算法) - 死锁的检测和解除
允许死锁发生,系统负责检测出死锁并解除
- 预防死锁(静态策略)
2.4.2 死锁的处理策略-预防死锁
- 破坏互斥条件
- 将临界资源改造为可共享使用的资源(如SPOOLing技术)
- 缺点:可行性不高,很多时候无法破坏互斥条件
- 破坏不剥夺条件
- 方案一,申请的资源得不到满足时,立即释放拥有的所有资源
- 方案二,申请的资源被其他进程占用时,由OS协助剥夺(考虑优先级)
- 缺点:实现复杂;剥夺资源可能导致部分工作实效;反复申请和释放导致系统开销大;可能导致饥饿
- 破坏请求和保持条件
- 运行前分配好所需的资源,之后一直保持
- 缺点:资源利用率低;可能导致饥饿
- 破坏循环等待条件
- 给资源编号,必须按编号从小到大的顺序申请资源
- 缺点:不方便增加新设备;会导致资源浪费;用户编程麻烦
2.4.3 死锁的处理策略-避免死锁
处于不安全状态未必发生了死锁,但死锁一定发生在不安全状态
银行家算法的核心思想:
在资源分配之前预先预判这次分配是否会导致系统进入不安全状态,以此决定是否答应资源分配请求
2.4.4 死锁的处理策略-检测和解除
-
检测
-
数据结构:资源分配图
本质——图
- 两种节点
- 进程节点
- 资源节点
- 两种边
- 进程节点——>资源节点(请求边)
- 资源节点——>进程节点(分配边)
- 两种节点
-
死锁检测算法
后期时间充裕可以自己动手实现- 依次消除与不阻塞进程相连的边,直到无边可消
- 注:所谓不阻塞进程是指其申请的资源数还足够的进程
- 死锁定理:若资源分配图是不可完全简化的,说明发生了死锁
-
-
解除
- 资源剥夺法
- 撤销进程法(终止进程法)
- 进程回退法
从这几个方面考虑- 进程优先级
- 已执行多长时间
- 还要多久能完成
- 进程已经使用了多少资源
- 进程是交互式的还是批处理式的
第3章 内存管理
3.1 内存管理概念
3.1.1 内存的基础知识
- 进程运行的基本原理
- 指令的工作原理
操作码+若干参数(可能包含地址参数) - 从写程序到程序运行
- 编辑源代码文件
- 编译
由源代码文件生成目标模块 - 链接
由目标模块生成装入模块,链接后形成完整的逻辑地址 - 装入
将装入模块装入内存,装入后形成物理地址
- 三种连接方式
- 静态链接:装入前链接成一个完整装入模块
- 装入时动态链接:运行时边装入边链接
- 运行时动态链接:运行时需要目标模块才装入并链接
- 三种装入方式
- 绝对装入
编译时产生绝对地址 - 可重定位装入==(静态重定位)==
装入时将逻辑地址转换为物理地址 - 动态运行时装入==(动态重定位)==
运行时将逻辑地址转换为物理地址,需设置重定位寄存器
- 绝对装入
- 指令的工作原理
3.1.2 内存管理的概念
- 内存空间的分配与回收
- 内存空间的扩充(实现虚拟性)
- 地址转换
- OS负责实现逻辑地址到物理地址的转换
- 三种方式
- 绝对装入
编译器负责地址转换(单道程序阶段,无OS) - 可重定位装入
装入程序负责地址转换(早期多道批处理阶段) - 动态运行时装入
运行时才进行地址转换(现代OS)
- 绝对装入
- 存储保护
- 保证各进程在自己的内存空间内运行,不会越界访问
- 两种方式
- 设置上下限寄存器
- 利用重定位寄存器、界地址寄存器实现
- 重定位寄存器(又称基地址寄存器)
- 界地址寄存器(又称限长寄存器)
3.1.3 覆盖与交换(408大纲已删)
- 覆盖技术
- 一个固定区
- 存放最活跃的程序段
- 固定区中的程序段在运行过程中不会调入调出
- 若干覆盖区
- 不可能同时被访问的程序段可共享一个覆盖区
- 覆盖区中的程序段在运行过程中会根据需要调入调出
- 必须对程序员声明覆盖结构,OS完成自动覆盖
- 缺点:对用户不透明,增加了用户编程负担
- 一个固定区
- 交换技术
- 内存紧张时,换出某些进程以腾出内存空间,再换入某些进程
- 磁盘分为文件区和对换区,换出的进程放在对换区
- 覆盖于交换的区别
- 覆盖是在同一个程序或进程中的
- 交换是在不同进程(或作业)之间的
3.1.4 连续分配管理方式
- 单一连续分配
- 只支持单道程序,内存分为系统区和用户区,用户程序放在用户区
- 无外部碎片,有内部碎片——无外有内
- 固定分区分配
- 支持多道程序,内存用户分为若干个固定大小的分区,每个分区只能装一道作业
- 无外部碎片,有内部碎片——无外有内
- 两种分区方式
- 分区大小相等
- 分区大小不等
- 动态分区分配
- 支持多道程序,在进程装入内存时,根据进程的大小动态地建立分区
- 无内部碎片,有外部碎片——无内有外
- 外部碎片“紧凑”技术来解决
- 回收内存分区时,可能遇到四种情况
空闲分区合并- 回收区前有相邻的空闲分区
- 回收区后有相邻的空闲分区
- 回收区前、后都有相邻的空闲分区
- 回收区前、后没有相邻的空闲分区
3.1.5 动态分区分配算法
- 首次适应(First Fit)
- 邻近适应(Next Fit)
- 最佳适应(Best Fit)
- 最坏适应(Worst Fit)
又称最大适应(Largest Fit)
3.1.6 基本分页存储管理方式
按信息的物理结构划分;只会产生少量内部碎片(页内碎片)
思想:把进程分页,各个页面可离散地存放到各个内存块中
- 页表
- 作用:实现从页号到物理块号的地址映射
- 一个进程对应一张页表,进程的每一页对应一个页表项,每个页表项由“页号”和“块号”组成
- 每个页表项的大小是相同的,页号是“隐含”的
- i号页表项存放地址 = 页表地址 + i * 页表项大小
- 逻辑地址结构——可拆分为\【页号P,页内偏移量】
- 页号 = 逻辑地址 / 页面大小;页内偏移量 = 逻辑地址 % 页面大小
- 如何实现地址转换
-
- 计算出逻辑地址对应的\【页号P,页内偏移量】
-
- 找到对应页面在内存中的存放位置(查页表)
-
- 物理地址 = 页面地址 + 页内偏移量
-
3.1.7 基本地址变换机构
-
页内寄存器(PTR)的作用
又称页表基址寄存器(PTBR)
存放页表起始地址和页表长度 -
地址变换过程
-
小细节
- 页内偏移量位数与页面大小之间的关系(要能用其中一个条件推出另一个条件,故页表地址结构是一维的)
- 页式管理中地址是一维的
- 实际应用中,通常使一个页框恰好能放入整个页表项
- 为方便找到页表项,页表通常是放在连续的内存块中
3.1.8 具有快表的地址变换机构
- TLB(快表)
Translation Lookside Buffer, 又称旁路转换缓冲/页表缓冲
一种高速缓存(Cache),用于存储最近使用的页表项,即从虚拟地址到物理地址的转换过程 - TLB与(普通)Cache的区别
- TLB缓存的是页表数据(即虚拟地址到物理地址的映射关系);Cache缓存的是实际数据或指令
- TLB主要用于加速地址转换过程;Cache主要用于提高指令和数据的读取速度
3.1.9 两级页表
-
单机页表存在的问题
- 所有页表现必须连续存放,页表过大时需要很大的连续空间
- 在一段时间内并非所有页面都用得到,没必要让整个页表常驻内存
-
两级页表
- 将长长的页表再分页
- 逻辑地址结构:(一级页号,二级页号,页内偏移量)
- 注意几个术语:页目录表/外层页表/顶级页表
-
如何实现地址变换
-
几个细节
- 多级页表中,各级页表的大小不能超过一个页面。若两级页表不够,可以分更多级
- 多级页表的访存次数(假设没有快表机构)——N 级页表访问一个逻辑地址需要 N + 1次访存
3.1.10 基本分段存储管理方式
按信息的逻辑结构划分;会产生外部碎片
-
分段
- 指在用户编程时,将程序按照逻辑划分为几个逻辑段
- 每个段在内存中占据连续空间,但各段之间可以不相邻
- 逻辑地址结构:(段号,段内地址)
-
段表
- 记录逻辑段到实际存储地址的映射关系
- 每个段对应一个段表项,各段表项长度相同,由段号(隐含)、段长、基址组成
-
地址变换
-
分段 VS 分页
- 分页对用户不可见,分段对用户可见
分页由OS管理,对用户透明;分段需要在用户编程时实现 - 分页的地址空间是一维的,分段的地址空间是二维的
- 分段更容易实现信息的共享和保护(纯代码/可重入代码 可以共享)
- 分页(单级页表)、分段访问一个逻辑地址都需要两次访存,分段存储中也可引入快表机构
- 分页对用户不可见,分段对用户可见
3.1.11 段页式管理方式
-
分段 + 分页
- 将地址空间按照程序自身的逻辑关系划分为若干个段,再将各段分为大小相等的页面
- 将内存空间分为与页面大小相等的一个个内存块,系统以块为单位为进程分配内存
- 逻辑地址结构:(段号,页号,页内偏移量)
-
段表、页表
- 每个段对应一个段表项。各段表项长度相同,由 段号(隐含)、页表长度、页表存放地址 组成
- 每个页对应一个页表项。各页表项长度相同,由 页号(隐含)、页面存放的内存块号 组成
-
地址变换
重定位寄存器(基地址寄存器)+界地址寄存器(限长寄存器)
-
访问一个逻辑地址所需访存次数
- 第一次—查段表、第二次—查页表、第三次—访问目标单元
- 可引入快表(TLB)机构,以段号和页号为关键字查询快表,即可直接找到最终的目标页面存放位置,引入快表后仅需一次访存
3.2 虚拟内存管理
3.2.1 虚拟内存的基本概念
- 传统存储管理方式的特征、缺点
- 一次性:作业数据必须一次性调入内存
- 驻留性:作业数据在整个运行期间都会常驻内存
- 局部性原理
- 时间局部性:现在访问的指令、数据在不久后可能会被再次访问
- 空间局部性:现在访问的内存单元周围的内存空间,很可能在不久后会被访问
- 高速缓存技术:使用频繁的数据放到更高速的存储器中
- 虚拟内存的定义和特征
- 程序不需要全部装入即可运行,运行时根据需要动态调入数据,若内存不够,还需换出一些数据
- 特征
- 多次性:无需再作业运行时一次性全部掉入内存,而是允许被分为多次调入内存
- 对换性:无需在作业运行时一直常驻内存,而是允许在作业运行过程中,将作业换入、换出
- 虚拟性:从逻辑上扩充了内存的容量,使用户看到的内存容量,远大于实际的容量
- 如何实现虚拟内存技术
- 访问的信息不在内存时,由OS负责将所需信息从外存调内存(请求调页功能)
- 内存空间不够时,将内存中暂时用不到的信息换出外存(页面置换功能)
- 虚拟内存的实现
- 请求分页存储管理
- 请求分段存储管理
- 请求段页式存储管理
3.2.2 请求分页管理方式
-
页表机制
- 在基本分页的基础上增加了几个表项(请求分页表)
-
缺页中断机构
-
找到页表后检查页面是否已在内存,若没在内存,产生缺页中断——中断处理需要I/O操作
-
缺页中断处理中,需要将目标页面调入内存,有必要时还要换出页面
-
缺页中断输入内中断,属于内中断中的“故障”,即可能被系统修复的异常
-
一条指令在执行过程中可能产生多次缺页中断
-
-
地址变换机构(与基本分页的对比)
- 找到页表项,需要检查页面是否在内存中
- 若页面不在内存中,需要请求调页
- 若内存空间不够,还需换出页面
- 页面调入内存后,需要修改相应页表项
3.2.3 页面置换算法
- 最佳置换算法OPT(Optimal)
性能最好,但实际无法实现 - 先进先出置换算法FIFO
唯一可能产生Belady异常的算法
基于队列实现 - 最近最久未使用置换算法(LRU, Least Recently Used)
性能最接近最佳置换,但需寄存器和栈的硬件支持
LRU是堆栈类算法 - 时钟置换算法(CLOCK)
- 简单时钟置换算法
又称最近未用算法(NRU, No Recently Used)
淘汰页面最多会经过两轮扫描 - 改进型时钟置换算法——淘汰页面最多会经过四轮扫描
- 简单时钟置换算法
3.2.4 页面分配策略、抖动、工作集
- 何时调入页面
-
系统拥有足够的对换区空间
-
系统缺少足够的对换区空间
-
UNIX方式
-
3.2.5 内存映射文件
第4章 文件管理
4.1 文件系统基础
4.1.1 初识文件管理
4.1.2 文件的逻辑结构
无结构文件(流式文件)
将数据按顺序组织成记录并积累、保存
有结构文件(记录式文件)
- 顺序文件
默认各记录在物理上顺序存储- 两种结构
- 串结构
记录顺序与关键字无关 - 顺序结构
记录按关键字顺序排列
- 串结构
- 定场记录、顺序结构的顺序文件可快速检索(根据关键字快速找到记录)
- 两种结构
- 索引文件
可支持随机存取
索引表按关键字排序,其本身也是一个定长记录的顺序文件,可支持快速检索 - 索引顺序文件
- 直接文件/散列文件(比较冷门)
给定记录的键值或通过散列函数转换的键值直接决定记录的物理地址
没有顺序的特性
联想DS中的哈希表
4.1.3 文件目录
- 文件目录的实现
- 一个文件对应一个FCB,一个FCB就是一个目录项,多个FCB组成文件目录
- 对目录的操作:搜索🔍、创建文件📁、删除文件❌、显示文件🖥️、修改文件📃
- 目录结构
- 单级目录结构
一个系统只有一张目录表,不允许文件重名 - 两级目录结构
不同用户的文件可以重名,但不能对文件进行分类 - 多级(树形)目录结构
- 不同目录下的文件可以重名,可以对文件进行分类,不方便文件共享
- 系统根据“文件路径”找到目标文件
- 从根目录出发的路径是“绝对路径”
- 从“当前目录”出发的路径是“相对路径”
- 无环图目录结构
- 实现了文件的共享
- 仅当共享计数器为0时,才真正删除该节点
- 单级目录结构
- 索引节点(inode)
- 除了文件名之外的所有信息都放到索引节点中,每个文件对应一个索引节点
- 目录项中只包含文件名、索引节点指针,因此每个目录项的长度大幅减小
- 由于目录项长度减少,因此每个磁盘块可以存放更多个目录项,因此检索文件时磁盘I/O的次数就少了很多
4.1.4 文件的物理结构
又称文件分配方式
内存与磁盘之间的数据交换(即读/写操作、磁盘I/O)都是以“块”为单位进行的。即每次读入一块,或每次写出一块
文件分配方式
-
连续分配
可用紧凑来处理碎片,但是需要耗费很大的时间代价
-
链接分配
![[截屏2024-07-21 20.18.35.png]]- 隐式链接
- 显式链接
-
索引分配
4.1. 5 逻辑结构 VS 物理结构
4.1.6 文件存储空间管理
- 存储空间的划分与初始化
- 文件卷(逻辑卷),目录区、文件区的概念
- 目录区包含文件目录、空闲表、位示图、超级块等用文件管理的数据
- 空闲表法
- 空闲表中记录每个连续空闲区的起始盘块号、盘块数
- 分配时可采用
- 空闲链表法
- 空闲盘块链
- 以盘块为单位组成一条空闲链
- 分配时从链头取出空闲块,回收时将空闲块查到链尾
- 空闲盘区链
- 以盘区为单位组成一条空闲链
- 分配时可采用首次适应、最佳适应等策略;回收时注意相邻空间盘区合并的问题
- 空闲盘块链
- 位示图法
- 一个二进制对应一个盘块
(字号,位号)或(行号,列号)与盘块号一一对应 - 重要考点:推算出块号->(字号,位号)之间的相互转换公式
- 需要注意的题目条件
- 二进制位0/1 到底在哪个代表空闲,哪个代表不空闲
- 字号、位号、盘块号到底是从0开始还是从1开始
- 一个二进制对应一个盘块
- 成组链接法
难以文字描述,很难作为考题
UNIX采用的策略,适合大型文件系统
4.1.7 文件的基本操作
4.1.8 文件共享
4.1.9 文件保护
4.2 文件系统
4.2.1 文件的层次结构(考纲不要求)
4.2.2 文件系统的全局结构(布局)
- 物理格式化
即低级格式化——划分扇区,检测坏扇区,并用备用扇区替换坏扇区 - 逻辑格式化
逻辑格式化后,磁盘分区(分卷 Volume), 完成各分区的文件系统初始化
注:逻辑格式化后,灰色部分就有实际数据了,白色部分还没有数据
4.2.3 虚拟文件系统
第5章 输入/输出管理
5.1 I/O管理概述
5.1.1 I/O设备的概念和分类
5.1.2 I/O控制器
I/O设备由 机械部件 + 电子部件(I/O控制器、设备控制器) 组成
5.1.3 I/O控制方式🌟
通道 = 阉割版CPU
通道程序 = 任务清单
- 程序直接控制方式
- 中断驱动方式
- DMA方式
- 通道控制方式
5.1.4 I/O软件层次结构
- 用户层(I/O)软件
- 设备独立性软件
- 设备驱动程序
- 中断处理程序
- 硬件
5.1.5 输入输出应用程序接口和驱动程序接口
-
输入输出应用程序接口
- 字符设备接口
- 块设备接口
- 网络设备接口
又称网络套接字(socket)接口
-
(设备)驱动程序接口
-
阻塞/非阻塞 I/O
5.2 设备独立性软件
5.2.1 I/O核心子系统
-
I/O调度
-
设备保护
5.2.2 假脱机技术
SPOOLing技术
- 脱机技术
- 外围控制机+更高速的设备——磁带
- 作用:缓解设备与CPU的速度矛盾,实现预输入、缓输出
- 假脱机技术
- 又叫SPOOLing技术,用软件的方式模拟脱机技术
- 输入井和输出井——模拟脱机输入/输出时的磁带
- 输入进程和输出进程——模拟脱机输入/输出时的外围控制机
- 输入缓冲区和输出缓冲区——内存中的缓冲区,输入、输出时的“中转站”
- 共享打印机
用SPOOLing技术将独占的打印机“虚拟”成共享打印机
5.2.3 设备的分配与回收
主要还是设备的分配
-
应考虑的因素
- 固有属性
独占设备、共享设备、虚拟设备(SPOOLing) - 分配算法
先来先服务、优先级高者优先、短任务优先等 - 安全性
安全分配方式、不安全分配方式
- 固有属性
-
静态分配与动态分配
静态分配:进程运行前为其分配全部所需资源,运行结束后归还资源
动态分配:进程运行过程中动态申请设备资源 -
设备分配管理中的数据结构
- 设备控制表(DCT, Device Control Table)
每个设备对应一张DCT,关键字段:类型/标识符/状态/指向COCT的指针/等待队列指针 - 控制器控制表(COCT, Controller Control Table)
每个控制器对应一个COCT,关键字段:状态/指向CHCT的指针/等待队列指针 - 通道控制表(CHCT, Channel Control Table)
每个控制对应一张CHCT,关键字段:状态/等待队列指针 - 系统设备表(SDT, System Device Table)
记录整个系统中所有设备的情况,每个设备对应一个表目,关键字段:设备类型/标识符/DCT/驱动程序入口
- 设备控制表(DCT, Device Control Table)
-
设备分配的步骤
- 根据进程请求的物理设备名找到系统设备表SDT;根据SDT找到设备控制表DCT并分配设备;根据DCT找到控制器控制表COCT并分配控制器;根据COCT找到通道控制表CHCT并分配通道
- 注:只有设备、控制器、通道三者都分配成功时,这次设备分配才算成功,之后便可启动I/O设备进行数据传送
- 缺点:用户编程时必须使用“物理设备名”,若换了一个物理设备,则程序无法运行,若进程请求的物理设备正在忙碌,则即使系统中还有同类型的设备,进程也必须阻塞等待
-
设备分配步骤的改进
- 用户编程时使用逻辑设备名申请设备,OS负责实现从逻辑设备名到物理设备名的映射(通过逻辑设备表LUT, Logical Unit Table)
- 逻辑设备表的设置问题
- 整个系统只有一张LUT:各用户所用的逻辑设备名不允许重复
- 每个用户一张LUT:各个用户的逻辑设备名可重复
5.2.4 缓冲区管理
- 缓冲区的概念
- 一般利用内存作为缓冲区
- 缓解CPU与I/O设备的速度矛盾、减少对CPU的中断频率、解决数据粒度不匹配的问题、提高CPU与I/O设备之间的并行性
- 单缓冲
- 设备—(T)—缓冲区—(M)—工作区—©—处理
- 处理一块数据平均耗时 Max(C, T) + M
- 分析问题的初始状态:工作区满,缓冲区空
- 双缓冲
- 处理一块数据平均耗时 Max(T, C + M)
- 分析问题的初始状态:工作区空,一个缓冲区满,另一个缓冲区空
- 循环缓冲
多个缓冲区链接成缓冲队列,in指针指向第一个空缓冲区,out指针指向第一个满缓冲区 - 缓冲池
- 三个队列:空缓冲队列、输入队列、输出队列
- 四种工作缓冲区
用于收容输入数据的工作缓冲区、用于提取输入数据的工作缓冲区
用于收容输出数据的工作缓冲区、用于提取输出数据的工作缓冲区
5.3 磁盘和固态硬盘
5.3.1 磁盘的结构
5.3.2 磁盘调度算法🌟
- 一次磁盘/写操作需要的时间
- 寻道时间(寻找时间):启动磁臂、移动磁头所花的时间
- 延迟时间:将目标扇区转到磁头下面所花的时间
- 传输时间:读/写 数据花费的时间
- 磁盘调度算法
- 先来先服务(FCFS)
按访问请求到达的先后顺序进行处理 - 最短寻找时间优先(SSTF)
- 每次都优先响应距离磁头最近的磁道访问请求
- 贪心算法的思想、能保证眼前最优,但无法保证总的寻道时间最短
- 缺点:可能导致饥饿
- 扫描算法(电梯算法、SCAN)
- 只有磁头移动到最边缘的磁道时才可以改变磁头移动方向
- 缺点:对各个位置磁道的响应频率不平均
- 循环扫描算法(C-SCAN)
只有磁头朝某个方向移动时才会相应请求,移动到边缘后立即让磁头返回起点,返回途中不响应任何请求 - 低频考点
LOOK算法
SCAN算法的改进,只要在磁头移动方向上不再有请求,就立即改变磁头方向
C-LOOK算法
C-SCAN算法的改进,只要在磁头移动方向上不再有请求,就立即让磁头返回
- 先来先服务(FCFS)
5.3.3 减少磁盘延迟时间的方法
5.3.4 磁盘的管理
5.3.5 固态硬盘SSD
与计组是同一个考点,OS更侧重考察 “读写性能特性” 和 “磨损均衡技术”