2.1 进程与线程
"程序是静态的菜谱,进程是动态的做菜过程。"
- 进程——程序在某个数据集上的一次动态执行过程,是系统进行资源分配的基本单位。
- 程序——静态的指令集合,存成文件放在磁盘上;一个程序可以对应多个进程(打开两个记事本就是两个进程)。
- 进程由程序段、数据段、PCB(进程控制块)三部分组成;PCB 是进程存在的唯一标志——这句话是考点。
进程 vs 线程(对比表必背):
| 进程 | 线程 | |
|---|---|---|
| 定位 | 资源分配的基本单位 | CPU 调度的基本单位 |
| 资源 | 拥有独立地址空间和资源 | 共享所属进程的资源(同一进程内线程共享内存) |
| 开销 | 创建、切换、通信开销大 | 切换开销小、通信方便(直接读写共享变量) |
| 关系 | 一个进程可包含多个线程 | 线程不能独立于进程存在 |
进程的特征(了解)
- 动态性(最基本特征,有生命周期)、并发性、独立性、异步性、结构性。
课堂练习(3 题)
- 进程存在的唯一标志是什么? 答:PCB(进程控制块)。
- CPU 调度的基本单位是进程还是线程? 答:线程(进程是资源分配的基本单位,线程是调度的基本单位)。
- 同一个进程内的多个线程共享什么?各自的私有内容是什么? 答:共享进程的内存空间和资源;各自有独立的栈和寄存器现场(执行上下文)。
2.2 进程状态与转换(必考图)
三态图背下来,转换条件能填出箭头上的字。
三种基本状态的准确定义
- 就绪——万事俱备,只差 CPU。
- 运行——正在占用 CPU 执行。
- 阻塞(等待)——在等某个事件(I/O 完成、信号量),给它 CPU 也没用。
易错(选择题高发)
- 阻塞 → 运行是错的:阻塞的进程事件完成后只能先回到就绪,再被调度才能运行。
- 就绪 → 阻塞是错的:阻塞必须由正在运行的进程主动发起(发起 I/O),没上过 CPU 的程序无从阻塞。
课堂练习(3 题)
- 进程正在执行 I/O 请求后进入什么状态?I/O 完成后又进入什么状态? 答:运行 → 阻塞;I/O 完成后阻塞 → 就绪(不能直接回运行)。
- 时间片用完的进程从运行变成什么状态? 答:就绪。
- 下列转换哪个不可能发生:A. 运行→阻塞 B. 阻塞→运行 C. 就绪→运行 D. 运行→就绪 答:B(阻塞不能直接到运行,必须先到就绪再被调度)。
2.3 同步与互斥:PV 操作(核心考点)
软考最爱出的一种题:在程序的①②③处填 P 或 V。学会本节有保底分。
两个概念先分清
- 互斥——多个进程抢同一个资源(打印机、变量),同一时刻只许一个用。争的是"我能不能进"。
- 同步——多个进程有先后配合关系(生产完才能消费、先算完 a 再算 b)。争的是"你完没完"。
- 被争夺的资源叫临界资源,访问它的代码段叫临界区,同一时刻只允许一个进程处于临界区。
P、V 操作的定义(信号量机制)
P(S):S = S − 1 ;若 S < 0,则本进程阻塞(进等待队列) V(S):S = S + 1 ;若 S ≤ 0,则唤醒一个等待进程 理解:S 代表"可用的资源数"(含负数时其绝对值表示排队等待的进程数)。 申请资源用 P(减),释放资源用 V(加)——先 P 后用,用完 V,成对出现。
两种最基本的用法(模板要能默写)
① 互斥(信号量初值 = 1):
P(mutex) // 进门先申请;第一个进程拿到,后来的堵在门外
临界区:使用打印机 / 改共享变量
V(mutex) // 出门还钥匙
② 同步(先做 A,后做 B;信号量初值 = 0):
进程甲:执行 A 动作 → V(S) // 做完 A 就"发信号"
进程乙:P(S) → 执行 B 动作 // 等信号到了才开始 B
互斥信号量初值为什么是 1?
- 初值 = 资源数。打印机只有一台 → S=1:第一个进程 P 后 S=0 顺利进入; 第二个进程 P 后 S=−1 被阻塞排队;第一个进程 V 后 S=0 并唤醒排队的进程。
- 同步信号量初值 = 0:因为 B 必须等 A 发信号(V)之后才能通过 P。
易错
- P 是申请(减),V 是释放(加),方向记反必错。
- 互斥的两个进程里,P/V 必须成对且在同一进程内包住临界区;别只 P 不 V(死锁)或先 V 后 P。
课堂练习(3 题)
- 互斥信号量初值应该设多少?同步信号量(先后关系)初值呢? 答:互斥初值 1;同步初值 0(等对方 V 之后才能 P 通过)。
- 进程执行 P(S) 后 S 由 0 变为 −1,说明什么? 答:该进程被阻塞,进入等待队列(此时有 1 个进程在等)。
- 信号量 S 当前为 −2,执行一次 V(S) 后 S 变成多少?发生什么? 答:V 先加 1,S 变为 −1;因结果 ≤ 0,唤醒一个等待进程(原本有 2 个在排队,唤醒后还剩 1 个)。
2.4 PV 操作经典题型(生产者-消费者)
考试就爱考这个模型的填空。把这道题吃透,遇到就稳。
场景:有大小为 N 的缓冲区。生产者进程生产一个产品放入缓冲区,放满 N 个就等一下; 消费者进程每消费一个产品腾出一个位置,缓冲区空就等一下。
初始信号量: mutex = 1 // 互斥访问缓冲区
empty = N // 空位数量(初始全部是空的)
full = 0 // 已有产品数(初始没有产品)
生产者进程: 消费者进程:
循环 { 循环 {
生产一个产品 P(full) // 有货吗?没有就等
P(empty) // 有位置吗?没有就等 P(mutex) // 抢缓冲区锁
P(mutex) // 抢缓冲区锁 从缓冲区取一个产品
把产品放入缓冲区 V(mutex) // 还锁
V(mutex) // 还锁 V(empty) // 空位 +1(通知生产者)
V(full) // 产品 +1(通知消费者) 消费掉产品
} }
解题三步法
- 找资源:缓冲区本身(互斥 mutex)、空位 empty、产品 full。
- 定初值:互斥 1;空位 = 容量 N;产品 = 0。
- 排操作顺序:就资源数量做 P(不够就等),做完动作做 V(通知别人)。 先对资源 P,再对互斥 P(顺序反了可能死锁)。
课堂练习(3 题)
- 缓冲区容量 N=10,empty 与 full 的初始值分别是多少? 答:empty=10,full=0。
- 如果把生产者的 P(empty) 与 P(mutex) 顺序互换(先 P(mutex) 后 P(empty)),可能出什么问题? 答:可能死锁——生产者占着互斥锁等空位,而腾空位需要消费者拿到互斥锁,互相等待。
- 生产者放入产品后 V(full) 的作用是什么? 答:通知等待的消费者"有货了";若消费者在等待则唤醒它。
2.5 死锁:四个必要条件必背
"产生死锁的条件"考的是四件套,缺一不可——答题先写这四条。
死锁的四个必要条件
- 互斥——资源同一时刻只能被一个进程占用。
- 请求并保持(占有并等待)——拿着手里的,还想要别的。
- 不可剥夺(不可抢占)——资源只能由占有者主动释放。
- 循环等待——存在一条进程—资源的环形等待链(A 等 B 的资源,B 等 A 的)。
对策:预防 / 避免 / 检测解除
- 预防——破坏四个条件之一(如资源一次性全部分配,破坏"请求并保持";按序申请资源,破坏"循环等待")。
- 避免——分配前先判断安全性,经典算法是银行家算法(知道名字与用途即可)。
- 检测与解除——允许发生,定期查死锁,然后剥夺资源/撤销进程来解除。
顺带认识:死锁(互相等,全动不了)、活锁(都在让路,谁也不前进)、饥饿(优先级低的一直排不上队)——概念题能区分即可。
课堂练习(3 题)
- 产生死锁的四个必要条件是什么? 答:互斥、请求并保持、不可剥夺、循环等待。
- "破坏循环等待"通常用什么办法? 答:给资源统一编号,规定所有进程必须按编号递增顺序申请资源。
- 判断:只要破坏了四个必要条件中的一个,死锁就一定不会发生。 答:正确——四条件必须同时成立才可能死锁,破坏其一即可预防。
2.6 进程调度与周转时间(会算)
给定作业到达时间与运行时间,算"谁先执行、周转时间多少"。
| 算法 | 思想 | 特点 |
|---|---|---|
| 先来先服务 FCFS | 按到达先后排队 | 公平;短作业排在长作业后面会等很久 |
| 短作业优先 SJF | 谁运行时间短谁先上 | 平均周转时间最短;长作业可能饿死 |
| 时间片轮转 RR | 每人一个时间片,轮着来 | 响应快,适合分时;切换开销大 |
| 优先级调度 | 优先级高的先上 | 灵活;要防低优先级饥饿(可用老化提高优先级) |
两个公式(计算题就靠它)
- 周转时间 = 完成时间 − 到达时间(在我的手里总共待了多久)。
- 带权周转时间 = 周转时间 ÷ 运行时间(待的时间是干活的几倍,越接近 1 越好)。
例题:三个作业 FCFS vs SJF
作业 A(到达 0,运行 7)、B(到达 2,运行 4)、C(到达 4,运行 1)。
FCFS(按到达先后:A→B→C): A:0−7 完成 → 周转 7 B:7−11 完成 → 周转 11−2=9 C:11−12 完成 → 周转 12−4=8 平均周转 = (7+9+8)/3 = 8 SJF(谁短谁先;A 先跑,2 时 B 到、4 时 C 到,C 比 B 短): A:0−7 → 周转 7 C:7−8 → 周转 8−4=4 B:8−12 → 周转 12−2=10 平均周转 = (7+4+10)/3 = 7 ← 更短,印证"短作业优先平均周转最短"
课堂练习(2 题)
- 某作业运行时间 5,等待后在第 12 时刻完成,到达时刻为 2,它的周转时间和带权周转时间是多少? 答:周转时间 = 12 − 2 = 10;带权周转时间 = 10 ÷ 5 = 2。
- 哪种调度算法的平均周转时间最短?(不考虑抢占) 答:短作业优先(SJF)。