用户态 v.s 内核态

核心概念与特权级

本质

用户态/内核态本质上是 CPU 的运行权限级别,是硬件提供的机制。 操作系统是这套机制的”使用者”和”管理者”。

  • 内核态(Ring 0):可执行一切指令,访问所有硬件资源
  • 用户态(Ring 3):受限,只能执行普通指令,无法直接操作硬件或访问内核数据结构

判断一个程序运行在什么态的唯一标准:其有无执行特权指令的能力

两种模式对比

内核态(Kernel Mode)用户态(User Mode)
CPU 特权级Ring 0(最高权限)Ring 3(最低权限)
执行指令所有指令(含特权指令)只能执行非特权指令
访问资源全部硬件、全部内存只能访问自己的地址空间
运行内容OS 内核、设备驱动、中断处理普通应用程序
崩溃后果系统崩溃(蓝屏/kernel panic)仅该程序崩溃
内存空间内核空间(共享)用户空间(隔离)

特权指令

只能在内核态执行的指令,包括:

  • 硬件控制:设置中断使能、修改处理器状态寄存器
  • 内存管理:修改页表、设置内存保护
  • 进程管理:创建/终止进程、更改进程优先级
  • I/O 操作:直接访问硬件设备或端口

中断屏蔽字寄存器属于 I/O 接口中的 I/O 端口,设置它属于 I/O 指令 → 特权指令。

状态切换与系统调用

状态切换的时机

用户态 → 内核态只能通过以下三种方式:

方式触发类型举例
系统调用主动用户程序请求 OS 服务(如 readfork
异常被动缺页、除零、越界、trap(访管指令)
外部中断被动I/O 完成、时钟中断

关键理解

  • 从用户态到内核态的切换只能通过上述三种途径(系统调用/异常/外部中断)
  • 访管指令(trap)在用户态执行,但会触发切换到内核态 — 执行 ≠ 触发后的状态
  • 一定要区分:调用指令在用户态,执行指令在内核态

切换流程(x86 为例)

用户程序执行 int 0x80(系统调用指令)
    ↓
CPU 自动:切换到 Ring 0(内核态),跳转到系统调用处理函数
    ↓
OS 执行相关服务
    ↓
执行 iret 返回用户程序
    ↓
CPU 自动:切回 Ring 3(用户态),恢复用户程序继续运行

系统调用

系统调用是用户态程序与 OS 内核之间的接口。

当应用程序需要执行特权操作(文件操作、网络通信、进程创建等)时,通过系统调用请求内核在内核态代为执行。

  • 涉及特权级转换:用户态 → 内核态 → 用户态,有性能开销
  • 常见类型:进程管理(fork/exec/wait)、文件操作(open/read/write)、内存管理、网络通信
  • 系统调用通过库函数实现,不在用户程序代码中
  • 系统调用一般不允许嵌套或递归

从内核转到用户只有 系统调用这一个法子?

审题的时候有想过,这个操作完成是指系统调用到内核态还是执行系统调用的内部程序,看完答案发现确实就是那么简单,但是其他选项还是要搞明白为什么不行

不同操作系统的系统调用接口不同

III 错误原因在于 Linux 与 Windows 的系统调用接口不同,例如创建进程分别对应 fork 和 CreateProcess。

系统调用 vs 过程调用

过程调用系统调用
是否引发中断是(软中断)
CPU 模式切换不切换(全程同一模式)用户态 → 内核态
需保存的内容只保存 PC保存 PC + PSW
被调用函数位置在程序代码中通过库函数,不在程序代码中
可否嵌套可以一般不允许
注意 PSW 存储的是 CPU 内核态 的标志

过程调用可以在用户态或内核态任一模式下发生,关键是不切换模式。

原语

处于 OS 最底层,由多条指令构成,不能被打断,运行时长较短,调用频繁。原语是内核态的原子操作。

内核架构与虚拟化

微内核 vs 宏内核

微内核宏内核
内核态运行最少核心功能(进程/线程管理、低级存储器管理、中断处理)全部 OS 功能
用户态运行文件系统、设备驱动、网络协议栈等
可靠性高(驱动崩溃不影响系统,隔离好)低(一部分失败 → 整个系统崩溃)
性能稍低(频繁上下文切换和消息传递)高(同一地址空间直接通信)
代表系统IOS、Fuchsia、HarmonyOS NEXTLinux、Windows、Android、传统 UNIX
  • 微内核设计原则:“机制与策略分离” — 机制保留在微内核,策略由外部服务器实现
  • 微内核性能低的原因:频繁的上下文切换(用户态↔内核态),而非内核代码本身慢

与虚拟化的关系

特权级扩展

Ring -1 (VMX root mode)  →  Hypervisor / VMM(最高权限)
Ring 0                    →  OS 内核
Ring 3                    →  用户程序
  • 1 型 VMM:直接运行在硬件上,是真正的内核态;客户机 OS 通过 VMM 间接使用硬件。1 型 VMM 本身属于用户态程序但能间接调用硬件 — 无法一元论,重点看实际运行

  • 2 型 VMM:运行在宿主机 OS 之上,作为用户态进程


总结

跨章节关联

  • 进程管理:内核空间具有更高特权级别,对用户程序不可见;Idle 进程(PID 0)始终在内核态运行;线程模型分纯用户态/纯内核态/混合方案

  • 内存管理:共享内存是最快的 IPC,无需进入内核态;mmap 消除用户态↔内核态的缓冲区拷贝;堆内存分配器(malloc/free)是动态分区思想下沉到用户态

  • I/O 管理:设备驱动程序运行在内核态,直接访问设备寄存器和端口;中断处理程序运行在内核态

  • 文件管理read/write 系统调用涉及用户态→内核态切换

记忆点

  • 判断状态的唯一标准:有无执行特权指令的能力

  • 访管指令 trap:在用户态执行,触发切换到内核态 — 执行 ≠ 触发后状态

  • 系统调用需保存 PSW,过程调用只需保存 PC(因为系统调用要切换 CPU 模式)

  • 微内核性能低 是因为频繁上下文切换,不是内核代码本身慢

  • 中断发生后:CPU 自动切换到内核态,由中断处理程序在内核态执行

易错点

  1. 系统调用 ≠ 过程调用:前者切换 CPU 模式,后者不切换;前者需保存 PSW,后者只需保存 PC
  2. 1 型 VMM 的态:不能简单归为”用户态”或”内核态”,要看实际运行时特权指令能力
  3. 让权等待:只有阻塞(如信号量 wait)才能让出 CPU,while 循环忙等做不到让权

静态重定位 vs 动态重定位

考频:高 | 选择题常考

核心区别

静态重定位动态重定位
转换时机装入时一次性每次访问时实时
能否移动❌ 地址锁死✅ 更新寄存器
支持对换

记忆点

  • 静态 = 焊死:地址硬编码,动不了 → 没法对换(并且静态重定位用的基地址是 随机空闲内存块的开头地址,不能自由分配)

  • 动态 = 轮子:重定位寄存器(Base),物理地址 = 逻辑地址 + Base → 随便换

  • 关键公式物理地址 = 逻辑地址 + Base

易错点

  • 静态重定位可以用于多道程序,但会产生外部碎片

  • 对换 vs 页面置换

对换(Swapping)页面置换(Page Replacement)
单位整个进程(PCB + 全部页面)单个页面
时机内存紧张时,把低优先级进程整体换出到磁盘缺页时,内存满,选一个页面换出
实现条件需要动态重定位 (利用PDBR, 进程要能移动)需要虚拟内存支持

分页存储管理

考频:极高 | 选择 + 综合

核心定义

将进程和内存都切成固定大小的块(页/页框),进程的页可以装入内存的任意页框。

内部碎片

分页会产生内部碎片,原因:

  • 页大小固定(如4KB)
  • 进程最后一页可能装不满
  • 剩余空间无法利用,形成内部碎片

举例:进程大小17KB,页大小4KB

页0:4KB(满)
页1:4KB(满)
页2:4KB(满)
页3:4KB(只用1KB,内部碎片3KB)

碎片对比

分页分段
内部碎片(最后一页可能不满)
外部碎片无(页框可任意分配)(连续分配导致)

记忆点

  • 分页 = 固定大小 → 有内部碎片

  • 分段 = 可变大小 → 有外部碎片


请求分页机制

考频:极高 | 选择 + 综合

基本分页 vs 请求分页

基本分页请求分页
页表项内容物理块号物理块号 + Valid位 + 磁盘索引
地址转换直接查表得块号先看Valid位,=1则同基本分页,=0则触发缺页
物理地址公式块号 × 页大小 + 偏移块号 × 页大小 + 偏移(一样)
PTBR指向页表起始位置指向页表起始位置(一样)
“请求”含义用到哪页才调入哪页,不是装入时全部放入内存

缺页的判定逻辑

CPU访问虚拟地址
    ↓
TLB查找 → 命中 → 直接得到物理地址(无缺页)
    ↓ 未命中
查页表 → Valid=1 → 得到物理地址(无缺页)
    ↓ Valid=0 页表本身不在内存
触发缺页异常

结论:TLB和页表中都找不到有效映射 → 缺页。这两个是地址转换的全部途径,都没有就是缺页。

缺页处理的过程

发生缺页
    ↓
有空闲页框?
   ├── 是 → 直接装入(无需替换)
   └── 否 → 先替换(换出一页腾空间)→ 再装入

注意

替换页面时,我们是在页表中找算法给定的页框(当前页面优先级比页框中之前装入的页面优先级要高)可以替换

替换是装入的前置步骤

页表作为页框中的数据

核心思想:页表本身也是页面,也占物理页框,也有虚拟地址

页表是"数据" → 存在某个物理页框中 → 这个页框对应一段虚拟地址
                ↑
        页目录/上级页表的页表项指向这里

页表项的虚拟地址推算

题目特征:告诉你页表起始的虚拟地址,要求算出某个页表项的虚拟地址范围

万能解法

已知:页表起始虚拟地址VA_start,页大小4KB,页表项4B

步骤:

1. 页表占多少页? → 页表总项数 = 每页能放的项数 = 4KB/4B = 1024项
   
2. 页表本身占几页? → 项数 × 4B / 页大小 = 1024×4B/4KB = 1页
   
3. 该页的虚拟页号 = VA_start对应的页号
   
4. 页表项i的虚拟地址 = VA_start + i × 4B

速算模板

页表起始虚拟地址:0x00400000
页大小:4KB = 0x1000
页表项大小:4B

求第8个页表项的虚拟地址:
VA = 0x00400000 + 8 × 4 = 0x00400020

求该页表项所在的虚拟页号:
页号 = 0x00400020 >> 12 = 0x00400 → 即第1024页

多级页表的”递归”本质

页目录本身 → 也是页面 → 也有虚拟地址 → 也存在某个页框中
    ↓
页目录项指向的页表 → 也是页面 → 也有虚拟地址
    ↓
页表项指向的数据页 → 也是页面 → 也有虚拟地址

每一级都是一样的结构:虚拟地址 → 查表 → 得到下一级的物理地址

对换区 vs 文件区

教材三种调页来源

情况页面来源理论依据
对换区足够全部从对换区调入对换区连续分配,I/O更快
对换区不够不修改的从文件区,修改的从对换区节省对换区空间
UNIX方式首次从文件区,换出后放对换区不预先拷贝,按需加载

实际OS的做法(Unix/Linux)

  • 第一次访问 → 从文件区调入(因为页面还没被修改过)
  • 换出后再调入 → 从对换区调入(因为已经是脏页)
  • 加大对换区不影响调页速度:首次访问不走对换区,后续访问本来就走对换区

考试中的矛盾点(2014真题)

  • 教材从理论出发:对换区大→调页快(因为页表可以从对换区调入)
  • 出题从实际出发:实际OS首次访问走文件区,对换区大小不影响调页速度
  • 结论:选项III(增大交换区)不能加快虚实地址转换,因为地址转换靠TLB+页表查找,跟对换区无关

分配策略 vs 替换策略

四种组合

局部替换(只能换自己的)全局替换(可以换别人的)
固定分配✅ 合理矛盾
可变分配⚠️ 不常见✅ 合理

唯一矛盾的组合:固定分配 + 全局替换

  • 固定分配 = 每个进程页框数锁死
  • 全局替换 = 可以从其他进程拿页框
  • 两个前提互相打架,逻辑不通

应用场景

组合应用特点
固定分配 + 局部替换实时系统页框数确定,性能可预测
可变分配 + 全局替换通用OS(Linux/Windows)灵活调整,实现简单

Belady 异常

定义

在某些页面置换算法(特别是 FIFO)中,增加页框数量反而导致缺页次数增加,违背”更多内存 → 更少缺页”的直觉,这种异常叫做 Belady 异常

经典例子

页面访问序列:1, 2, 3, 4, 1, 2, 5, 1, 2, 3, 4, 5

页框数FIFO 缺页次数
3 个页框9 次
4 个页框10 次(反而更多!)

各类算法

算法会出现 Belady 异常?原因
FIFO❌ 会不是栈算法,页框多时历史信息丢失,无法包容小容量的驻留集(混乱算法)
OPT✅ 不会栈算法:k 帧的驻留集 ⊆ k+1 帧的驻留集
LRU✅ 不会同为栈算法,基于时间局部性
CLOCK❌ 会CLOCK 算法是对LRU的近似,但不是严格的栈算法,它依赖访问位和指针扫描

记忆点

  • Belady 异常 = FIFO 专属考点(OPT/LRU 这类栈算法不会出现)
  • 栈算法的性质:页框越多,驻留集只会更大或不变 → 缺页单调不增
  • FIFO 不满足栈性质:队头淘汰与”驻留时长”相关,与”未来是否使用”无关

分段存储管理

段地址说明

逻辑地址 = [段号S | 段内偏移W]
                ↓
        段表项 = [基址 | 段长]
                ↓
        越界检查:W >= 段长? → 是则越界中断(段错误)
                ↓
        物理地址 = 基址 + W

逐步解释

第1步:拆分逻辑地址

  • CPU给出的逻辑地址分两部分:段号S 和 段内偏移W
  • 本题中 S占8位,W占24位

第2步:查段表

  • 用段号S去查段表,找到对应的基址(段在物理内存的起始位置)和段长(该段有多大)

第3步:越界检查 ⚠️

  • 如果偏移量W ≥ 段长,说明访问超出了该段的范围
  • 触发段错误中断(就是程序崩溃时常见的 Segmentation Fault)

第4步:计算物理地址

  • 通过检查后:物理地址 = 基址 + W
  • 即从段的起点,偏移W个字节,就是实际的内存位置

段长的作用

越界检查(安全保护),不是用来计算地址

  • 基址:计算物理地址 = 基址 + 段内偏移
  • 段长:确保段内偏移 < 段长,否则越界中断

分页 vs 分段

分页分段
大小固定(如4KB)可变(程序实际大小)
需要段长吗不需要(每页都一样大)必须有(段大小不同)
越界检查页内偏移不可能越界段内偏移可能越界
目的内存利用率信息共享和保护

记忆点:段长是安全锁,防止程序越界访问其他段的内存


动态分区

内存空闲分区表 类似 磁盘空闲分区表 表项包含:分区起始地址,分区大小。

内存回收规则

回收时检查是否相邻,相邻则合并,不相邻则新增。

情况处理分区数变化
与前一个空闲区相邻合并-1
与后一个空闲区相邻合并-1
与前后都相邻三合一-2
与前后都不相邻新增+1

典例(2017真题)

空闲分区:[20K,40KB] [500K,80KB] [1000K,100KB] [200K,200KB]
回收:起始60K,大小140KB(范围60K-199K)

解题步骤

  • 回收区60K-199K与空闲区20K-59K相邻 → 合并为20K-199K(180KB)

  • 合并后20K-199K与空闲区200K-399K继续相邻(199K+1=200K)→ 三合一为20K-399K(380KB)

  • 结果:3个分区 [20K,380KB] [500K,80KB] [1000K,100KB]

  • 最佳适应按大小升序排序:链首 = 最小的 [500K, 80KB]

答案:B(3、500K、80KB)

偷鸡技巧

直接看起始地址判断是否相邻

  • 回收区起始地址 = 某空闲区起始地址 + 该空闲区大小 → 与该空闲区后邻
  • 回收区起始地址 + 回收区大小 = 某空闲区起始地址 → 与该空闲区前邻

本题速算

  • 回收区起始60K,空闲区20K大小40KB → 20K+40K=60K → 后邻,合并
  • 合并后结束199K,下一空闲区起始200K → 199K+1=200K → 继续相邻,三合一

注意事项

  • 边界判断起始地址 + 大小 是下一个块的起始,不是末尾地址 + 1

  • 最佳适应会重新排序:题目说”每次回收后重新排序”,答案可能是按大小排序后的链首

  • 别漏看”相邻”:回收区可能与多个空闲区同时相邻(前+后),要三合一


关联记忆

静态重定位 → 不能移动 → 不能对换 → 无虚拟内存

动态重定位 → 能移动 → 能对换 → 虚拟内存基础
         ↓
    请求分页(页面置换)
         ↓
    虚拟内存实现

文件管理

软硬链接 与 FCB

先说 FCB,原理上来说 FCB(文件控制块)是 目录 用来描述对应 文件的。

具体实现时,为了让用户能够高效调用文件,将 目录项(即 FCB)分割为两部分,实际目录项中只有 文件名 和 inode 号,另一部分放到了 索引表 中 (包含 文件类型、权限、所有者、文件大小、数据块指针 等)

正是因为这种现实中的 分割,给 软硬链接 的实现 铺垫了基础,

[硬链接]

不同文件名可以对应同一 inode 指向的文件,从而实现 共享同一份 文件数据
inode 内部维护着一个链接计数器,每创建一个硬链接,计数加一;删除一个文件名,计数减一;只有计数归零时,文件数据块才真正被释放。所以”删除文件”准确说是”删除一个目录项”

[软链接]

软链接 是一个独立的文件,有自己的 inode,文件内容存的是目标文件的路径字符串。所以软链接可以跨文件系统,但目标被删后软链接就悬空失效了;而硬链接不能跨文件系统,但任意一个链接都和原文件”平等”,没有主从之分

硬链接共享 inode,软链接存路径

单个文件最大长度计算

2012年真题 - 直接索引 + 混合索引

题目条件:系统最大容量 4TB,块大小 1KB,FCB 索引表区 512B

(1) 直接索引结构

块号最少字节数 = ?
├─ 4TB = 2^42 B
├─ 最大块数 = 2^42 / 2^10 = 2^32 块
├─ 块号需要表示到 2^32,需32位 → 4字节
├─ 索引表项数 = 512B ÷ 4B = 128项
└─ 最大文件长度 = 128 × 1KB = 128KB

记忆点:直接索引 = 每个索引项指向一个块, 索引项数 = 文件最大块数

(2) 混合索引结构

(起始块号6B + 块数2B + 直接索引 504B)

原方案:
├─ 连续部分:块数2B → 最大 2^16-1 = 65535块
├─ 直接索引:504B ÷ 6B = 84个索引项
├─ 总块数 = 65535 + 84 = 65619块
└─ 最大文件长度 ≈ 64.08MB

优化方案(使文件最大):
├─ 起始块号改4B(够用,系统最大块号2^32只需4B)
├─ 块数改4B(能表示2^32 - 1块,但是官方答案给的是 2^32)
├─ 连续部分最大 = 2^32块(受系统容量限制)
├─ 直接索引:(512-8)B ÷ 6B = 84项
├─ 总块数 = 2^32 + 84
└─ 最大文件长度 ≈ 4TB + 84KB

关键:优化时要先保证块号够用(4字节),再考虑块数字段


2014年真题 - 链接分配

题目条件:每块 1KB,指针 4B

链接分配的文件最大长度:
├─ 指针4B → 可寻址 2^32 个块
├─ 每块实际存数据 = 1KB - 4B = 1020字节
├─ 最大文件长度 = 2^32 × 1020B = 4080GB

记忆点:链接分配的限制是指针的寻址能力,不是块数


三种分配方式对比

分配方式文件最大长度限制因素本题最大长度
连续分配磁盘连续空间大小取决于最大连续空闲区
链接分配指针位数(寻址能力)≈4.08GB(4B指针,2进制换算)
索引分配索引表项数 × 块大小128KB(直接索引)

易错点

  • 链接分配计算时,要减去指针占用空间再乘块数
  • 索引分配要考虑索引表本身的大小限制
  • 优化混合索引时,块号字段优先保证够用(系统最大块数 = ,需 4 字节)

操作系统初始化与磁盘结构

核心结论

磁盘物理格式化   → 建立 扇区 + 磁道
磁盘分区        → 建立 磁盘分区表 + 引导扇区
磁盘逻辑格式化   → 建立 根目录 + inode表  (同文件系统有关)
操作系统初始化   → 建立 中断向量表(BIOS相关) 

四个阶段详解

1. 物理格式化

出厂前由厂商完成,把盘片划分为磁道、扇区。 用户买到硬盘时这一步已经做好了

2. 硬盘分区

把硬盘划分为若干独立区域,如 C 盘、D 盘。

一块硬盘
├── 分区1(C盘)
├── 分区2(D盘)
└── 分区3(D盘)

此时建立的是分区表——记录每个分区从哪里开始、到哪里结束。

3. 逻辑格式化

也称为 文件系统 格式化(软件层面)

对每个分区单独进行,选择文件系统类型( 等)。

类比:右键U盘 → 格式化 → 选择 NTFS,就是在做这一步。

格式化在分区内部建立两样东西:

根目录

  • 你打开U盘/C盘看到的那个最外层的空文件夹界面
  • 所有文件和文件夹都挂在它下面
  • 格式化会把旧的根目录清空重建

inode 表

根目录(你能看见)          inode表(看不见)
────────────────            ─────────────────
📁 我的照片/                #001 我的照片 → 位置第38块
  📄 photo1.jpg      →      #002 photo1.jpg → 大小3MB 位置第39块
  📄 photo2.jpg             #003 photo2.jpg → 大小2MB 位置第42块

根目录负责展示文件结构,inode表负责记录文件的真实信息,缺一不可。

4. 操作系统初始化

每次开机都要做

内核加载进内存后,正式运行前的准备工作

BIOS 负责初始化硬件,然后建立 中断向量表

中断向量表是什么? 支撑操作系统的内核

  • 存放各类中断的处理程序入口地址
  • 操作系统一切运行都依赖中断(I/O、系统调用、异常处理……)
  • 没有它,操作系统无法响应任何事件
  • 每次开机都要重新建立(存在内存里,不是磁盘)

真题回顾

答案:A

选项建立时机是否每次开机重建
A 中断向量表操作系统初始化✅ 是
B 文件系统根目录逻辑格式化❌ 否
C 硬盘分区表硬盘分区❌ 否
D inode表逻辑格式化❌ 否

易错点

前三个阶段(物理格式化、分区、逻辑格式化)建立的结构持久化存在磁盘上,开机后只是读取,不会重新创建。

只有中断向量表是每次开机时由操作系统初始化阶段重新建立的。


磁头读取数据的物理原理

考频:中 | 选择题偶尔考,综合题考

硬盘结构

盘片(高速旋转)
  ↑
磁头(悬浮在盘片上方,不接触)
  ↑
磁臂(控制磁头径向移动)

读取原理

盘片表面涂满磁性材料,每个微小区域的磁极方向代表 0 或 1:

↑ 磁极朝上 = 1
↓ 磁极朝下 = 0

磁头里有一个感应线圈,当盘片旋转,磁性区域从磁头下方划过时:

磁场变化 → 线圈产生感应电流 → 电流大小/方向 → 解读为0或1

这就是电磁感应,和初中物理一样的原理。

写入原理

反过来:

给线圈通电 → 产生磁场 → 改变盘片上该区域的磁极方向 → 写入0或1

为什么磁头不接触盘片

盘片转速极高(7200转/分),接触会划伤盘片,所以磁头悬浮在纳米级高度,靠气流维持间距。

这也是为什么硬盘怕震动——震动可能导致磁头撞上盘片,即磁头划伤(head crash),数据全毁。

何为访问

读一次是访问,写一次也是访问;

磁盘的内容是否从磁盘到主存再从主存到磁盘这一连续过程 无关!!!


进程同步与互斥

错题整理

【2016】进程互斥与线程并发

题目: 进程P1和P2均包含并发执行的线程,部分伪代码描述如下所示。

伪代码:

// 进程 P1
int x = 0;
Thread1() {
    int a;
    a = 1;
    x += 1;
}
Thread2() {
    int a;
    a = 2;
    x += 2;
}

// 进程 P2
int x = 0;
Thread3() {
    int a;
    a = x;
    x += 3;
}
Thread4() {
    int b;
    b = x;
    x += 4;
}

问题: 下列选项中,需要互斥执行的操作是()。
A. a = 1a = 2
B. a = xb = x
C. x += 1x += 2
D. x += 1x += 3

正确答案: C

要点:

  • 进程局部:每个进程有自己的局部变量 ab,但 x 是共享变量
  • 核心理解:只有对共享变量 x 的并发操作才需要互斥

【2018】让权等待

题目: 下列同步机制中,可以实现让权等待的是()。

A. Peterson 方法
B. swap 指令
C. 信号量方法
D. TestAndSet 指令

正确答案: C

要点:

  • while 循环做不到让权:Peterson、swap、TestAndSet 均使用 while 循环检测,进程在循环中忙等
  • 只有涉及 CPU 才能使进程阻塞离开:信号量方法中的 wait() 操作可使进程阻塞

【2016】TSL 指令实现互斥

题目: 使用 TSL(TestandSetLock)指令实现进程互斥的伪代码。

do {
while (TSL(&lock))critical section;
lock = FALSE;
} while (TRUE);

A. 退出临界区的进程负责唤醒阻塞态进程
B. 等待进入临界区的进程不会主动放弃CPU
C. 上述伪代码满足“让权等待”的同步准则
D. while(TSL(&lock))语句应在关中断状态下执行

正确答案: B(等待进入临界区的进程不会主动放弃 CPU)

要点:

  • 死等:进程在 while 循环中持续调用 TSL,属于忙等
  • while 循环出不来了:若 lock 为 TRUE,进程会一直循环检测

【2014】管道通信

题目: 下列关于管道(Pipe)通信的叙述中,正确的是()。

A. 一个管道可实现双向数据传输
B. 管道的容量仅受磁盘容量大小限制
C. 进程对管道进行读操作和写操作都可能被阻塞
D. 一个管道只能有一个读进程或一个写进程对其操作

正确答案: C(进程对管道进行读操作和写操作都可能被阻塞)

要点:

  • 单项半双工:管道通常是半双工(单向)通信
  • 内存相关:管道容量受内存大小限制,而非磁盘
  • 可以多个写:允许多个写进程

【2010】进程创建

题目: 下列选项中,导致创建新进程的操作是()。
I. 用户登录成功 II. 设备分配 III. 启动程序执行

A. 仅I、II
B. 仅II、III
C. 仅I、III
D. I、II、III

正确答案: C(仅 I、III:用户登录成功、启动程序执行)

要点:

  • 分时 创建新进程:用户登录成功(分时系统)会创建新进程
  • 设备分配:只是资源分配,不创建新进程

同步机制准则

  1. 空闲让进:临界区空闲时,允许一个进程立即进入
  2. 忙则等待:已有进程进入临界区时,其他进程必须等待
  3. 有限等待:保证进程在有限时间内进入临界区
  4. 让权等待:进程不能进入临界区时,应立即释放处理机(不一定要实现)

很有意思

软件实现方法

方法特点问题
单标志法两个进程交替进入可能违背空闲让进
双标志先检查先检查对方标志可能同时进入,违背忙则等待
双标志后检查先设置自己标志双方互相谦让,导致饥饿
Peterson算法标志+turn变量仍属于忙等

硬件实现方法

方法特点
Test-and-Set原子操作,忙等锁
Swap指令原子操作,忙等锁
关中断仅适用于单处理器

易错点

  • 局部变量 vs 共享变量:不同进程中的同名变量是独立的,只有共享变量需要互斥
  • 让权等待:只有阻塞(如信号量 wait)才能让出 CPU
  • 管道容量:受内存限制,非磁盘
  • 进程创建:设备分配不创建新进程

进程状态切换

状态切换的原因

切换方向原因主动/被动
就绪 → 运行被进程调度选中,获得 CPU被动(调度器决定)
运行 → 就绪时间片用完;被更高优先级进程抢占被动(CPU 被剥夺)
运行 → 阻塞请求 I/O、申请资源失败、wait() 信号量主动(自己发起等待)
阻塞 → 就绪I/O 完成、资源释放、signal() 唤醒被动(事件发生,他人唤醒)

判断口诀:看进程缺什么

  • 只缺 CPU → 就绪态

  • 缺 CPU 以外的资源(等事件)→ 阻塞态

典型阻塞事件:请求 I/O、等待信号量、等待消息、申请临界资源失败

时间片轮转 与 阻塞态

这是最容易混淆的一对关系,真题反复考:

对比项运行 → 就绪(时间片轮转)运行 → 阻塞
触发原因时间片用完、被抢占等待某事件(I/O、信号量)
进程意愿还想继续执行主动放弃 CPU 去等待
缺少资源只缺 CPU,不缺任何其他资源缺 CPU 以外的资源
恢复条件重新调度即可,随时能跑必须等事件发生才被唤醒

核心结论:时间片用完,进程进入就绪态(就绪队列尾部),绝不进入阻塞态。

时间片大小的权衡

  • 时间片太短:切换次数 = 变多,系统开销(上下文切换)增大
  • 时间片太长:响应时间变差,退化为 FCFS
  • 影响因素:响应时间、系统开销、进程数量(

时钟中断的作用:RR 算法靠时钟中断计时,中断发生后修改当前进程的剩余时间片,减到 0 则触发调度


【真题】时间片调度(第 26 题)

题目: 下列有关基于时间片的进程调度的叙述中,错误的是()。

A. 时间片越短,进程切换的次数越多,系统开销也越大
B. 当前进程的时间片用完后,该进程状态由执行态变为阻塞态
C. 影响时间片大小的主要因素包括响应时间、系统开销和进程数量等
D. 时钟中断发生后,系统会修改当前进程在时间片内的剩余时间

正确答案: B

要点:

  • B 错误(题眼):时间片用完,进程不缺任何资源,只是 CPU 被剥夺,转为就绪态回到就绪队列尾部;阻塞必须由”等待事件”引起
  • A 正确:切换次数随时间片缩短而增多,上下文切换开销变大
  • C 正确:响应时间、系统开销、进程数量共同决定时间片取值
  • D 正确:RR 靠时钟中断计时并修改剩余时间片

【2015】死锁避免 vs 死锁检测

题目: 若系统 S1 采用死锁避免方法,S2 采用死锁检测方法。下列叙述中,正确的是()。

I. S1 会限制用户申请资源的顺序,而 S2 不会
II. S1 需要进程运行所需的资源总量信息,而 S2 不需要
III. S1 不会给可能导致死锁的进程分配资源,而 S2 会

A. 仅 I、II  B. 仅 II、III  C. 仅 I、III  D. I、II、III

正确答案: B

要点:

  • I 错误:限制申请资源顺序是死锁预防(破坏循环等待条件)的手段,避免法不限制顺序
  • II 正确:死锁避免(银行家算法)必须预知进程的最大资源需求;检测法只需当前分配情况
  • III 正确:避免法只在系统处于安全状态时才分配;检测法照常分配,死锁发生后再检测并解除

三种处理策略层次

策略时机手段代价
死锁预防事前(静态)破坏四个必要条件之一(如限制申请顺序)资源利用率低
死锁避免事中(动态)银行家算法,需资源总量信息每次分配都要安全性检查
检测+解除事后资源分配图检测,剥夺/撤销进程死锁已发生,有损失

易错点

  • 时间片用完进就绪,不进阻塞:判断标准是”缺不缺 CPU 以外的资源”
  • 阻塞是主动行为:运行中的进程自己请求资源失败才阻塞;被唤醒是被动的
  • 限制申请顺序的是预防,不是避免:避免法(银行家算法)只看安全性,不限顺序
  • 银行家算法需要 Max 信息:检测法不需要进程未来的资源需求
  1. 管程是啥,管程为啥,管程干啥
  2. 编程语言不要局限于 c python java 实际上的编程语言范围及其宽广

看这个就行了

死锁的必要性条件:每个阻塞进程都少一个资源,构成一个资源需求环