feat: 增加同步互斥与死锁章节及OS README
This commit is contained in:
parent
c857cf21f0
commit
6f9d6b6202
|
|
@ -0,0 +1,341 @@
|
|||
## 笔记记录
|
||||
|
||||
### 要点 01 - 临界区与互斥基本概念
|
||||
|
||||
#### 临界资源与临界区
|
||||
|
||||
- **临界资源(Critical Resource)**:一次仅允许一个进程使用的资源
|
||||
- **临界区(Critical Section)**:访问临界资源的代码段
|
||||
|
||||
#### 临界区访问原则
|
||||
|
||||
| 原则 | 说明 |
|
||||
|------|------|
|
||||
| **空闲让进** | 无进程在临界区时,应允许一个请求进入的进程立即进入 |
|
||||
| **忙则等待** | 已有进程在临界区时,其他试图进入的进程必须等待 |
|
||||
| **有限等待** | 对请求进入的进程,应在有限时间内获准进入 |
|
||||
| **让权等待** | 进程不能进入临界区时应释放CPU(非必须,但现代OS推荐) |
|
||||
|
||||
#### 同步与互斥
|
||||
|
||||
- **互斥(Mutual Exclusion)**:同一时刻只允许一个进程进入临界区
|
||||
- **同步(Synchronization)**:多个进程之间因执行顺序约束而产生的协调关系
|
||||
|
||||
---
|
||||
|
||||
### 要点 02 - Peterson 算法
|
||||
|
||||
#### 算法实现
|
||||
|
||||
```c
|
||||
bool flag[2] = {false, false};
|
||||
int turn;
|
||||
|
||||
// 进程 Pi (i=0,1)
|
||||
flag[i] = true;
|
||||
turn = 1 - i;
|
||||
while (flag[1-i] && turn == 1-i);
|
||||
// 临界区
|
||||
flag[i] = false;
|
||||
// 剩余区
|
||||
```
|
||||
|
||||
#### 特点
|
||||
|
||||
满足互斥、空闲让进、有限等待,但**不满足让权等待**(忙等)。
|
||||
|
||||
---
|
||||
|
||||
### 要点 03 - 硬件互斥方法
|
||||
|
||||
#### 关中断
|
||||
|
||||
进入临界区前关中断,之后开中断。简单但关中断权限过大,不适用于多核。
|
||||
|
||||
#### TestAndSet 指令
|
||||
|
||||
原子操作:返回 `lock` 旧值并置为 `1`。
|
||||
|
||||
```c
|
||||
bool TestAndSet(bool *lock) {
|
||||
bool old = *lock;
|
||||
*lock = true;
|
||||
return old;
|
||||
}
|
||||
// 使用
|
||||
while (TestAndSet(&lock)); // 忙等
|
||||
// 临界区
|
||||
lock = false;
|
||||
```
|
||||
|
||||
#### Swap 指令
|
||||
|
||||
原子交换两个变量的值。
|
||||
|
||||
适用于多核,但仍是忙等。
|
||||
|
||||
---
|
||||
|
||||
### 要点 04 - 信号量机制
|
||||
|
||||
#### 整型信号量
|
||||
|
||||
```c
|
||||
int S = 1; // 资源数量
|
||||
wait(S) { while (S <= 0); S--; }
|
||||
signal(S) { S++; }
|
||||
```
|
||||
|
||||
仍是忙等,不满足让权等待。
|
||||
|
||||
#### 记录型信号量
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
int value; // 资源数量
|
||||
struct process *list; // 等待队列
|
||||
} semaphore;
|
||||
|
||||
wait(semaphore *S) {
|
||||
S->value--;
|
||||
if (S->value < 0) block(S->list);
|
||||
}
|
||||
|
||||
signal(semaphore *S) {
|
||||
S->value++;
|
||||
if (S->value <= 0) wakeup(S->list);
|
||||
}
|
||||
```
|
||||
|
||||
- `S->value < 0` 时,绝对值表示等待队列中的进程数
|
||||
- 满足**让权等待**
|
||||
|
||||
#### 两种信号量用法
|
||||
|
||||
- **互斥信号量**:初始为 1,`wait`/`signal` 成对出现在同一进程
|
||||
- **同步信号量**:初始为 0(或n),`wait`/`signal` 成对出现在不同进程
|
||||
|
||||
---
|
||||
|
||||
### 要点 05 - 生产者-消费者问题
|
||||
|
||||
#### 问题描述
|
||||
|
||||
一组生产者进程和一组消费者进程共享一个初始为空、大小为 n 的缓冲区。
|
||||
|
||||
#### 代码实现
|
||||
|
||||
```c
|
||||
semaphore mutex = 1; // 互斥访问缓冲区
|
||||
semaphore empty = n; // 空缓冲区数
|
||||
semaphore full = 0; // 满缓冲区数
|
||||
|
||||
// 生产者
|
||||
producer() {
|
||||
while (1) {
|
||||
produce();
|
||||
wait(empty);
|
||||
wait(mutex);
|
||||
buffer[in] = item; in = (in + 1) % n;
|
||||
signal(mutex);
|
||||
signal(full);
|
||||
}
|
||||
}
|
||||
|
||||
// 消费者
|
||||
consumer() {
|
||||
while (1) {
|
||||
wait(full);
|
||||
wait(mutex);
|
||||
item = buffer[out]; out = (out + 1) % n;
|
||||
signal(mutex);
|
||||
signal(empty);
|
||||
consume(item);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 易错点
|
||||
|
||||
`wait(empty)` 和 `wait(mutex)` 的顺序不可交换,否则可能死锁。
|
||||
|
||||
---
|
||||
|
||||
### 要点 06 - 读者-写者问题
|
||||
|
||||
#### 读者优先
|
||||
|
||||
```c
|
||||
semaphore rw = 1; // 写互斥
|
||||
semaphore mutex = 1; // 保护 read_count
|
||||
int read_count = 0;
|
||||
|
||||
writer() {
|
||||
wait(rw); write(); signal(rw);
|
||||
}
|
||||
|
||||
reader() {
|
||||
wait(mutex);
|
||||
if (read_count == 0) wait(rw);
|
||||
read_count++;
|
||||
signal(mutex);
|
||||
read();
|
||||
wait(mutex);
|
||||
read_count--;
|
||||
if (read_count == 0) signal(rw);
|
||||
signal(mutex);
|
||||
}
|
||||
```
|
||||
|
||||
#### 写者优先
|
||||
|
||||
增加一个 `w` 信号量,使写者到达后阻止后续读者进入。
|
||||
|
||||
---
|
||||
|
||||
### 要点 07 - 哲学家就餐问题
|
||||
|
||||
#### 问题描述
|
||||
|
||||
5 个哲学家围坐圆桌,每两人之间有一根筷子,哲学家只有同时拿到左右两根筷子才能进餐。
|
||||
|
||||
#### 代码实现
|
||||
|
||||
```c
|
||||
semaphore chopstick[5] = {1, 1, 1, 1, 1};
|
||||
semaphore mutex = 1; // 限制最多4人同时就餐,避免死锁
|
||||
|
||||
philosopher(int i) {
|
||||
while (1) {
|
||||
think();
|
||||
wait(mutex);
|
||||
wait(chopstick[i]);
|
||||
wait(chopstick[(i+1)%5]);
|
||||
signal(mutex);
|
||||
eat();
|
||||
signal(chopstick[i]);
|
||||
signal(chopstick[(i+1)%5]);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 防死锁策略
|
||||
|
||||
- 最多允许 4 人同时进餐(如上述代码)
|
||||
- 奇数号先左后右,偶数号先右后左
|
||||
|
||||
---
|
||||
|
||||
### 要点 08 - 吸烟者问题
|
||||
|
||||
#### 问题描述
|
||||
|
||||
三个吸烟者分别缺烟草、纸、胶水,一个供应者随机提供两种材料。
|
||||
|
||||
#### 代码实现
|
||||
|
||||
```c
|
||||
semaphore offer[3] = {0, 0, 0};
|
||||
semaphore finish = 0;
|
||||
int turn = 0;
|
||||
|
||||
provider() {
|
||||
while (1) {
|
||||
turn = rand() % 3;
|
||||
signal(offer[turn]);
|
||||
wait(finish);
|
||||
}
|
||||
}
|
||||
|
||||
smoker(int i) {
|
||||
while (1) {
|
||||
wait(offer[i]);
|
||||
smoke();
|
||||
signal(finish);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 要点 09 - 管程
|
||||
|
||||
#### 基本概念
|
||||
|
||||
**管程(Monitor)** 是一个高级同步原语,封装了共享变量和操作过程:
|
||||
|
||||
- 任一时刻最多只有一个进程在管程内执行
|
||||
- 通过 **条件变量(Condition Variable)** 实现同步:
|
||||
- `wait(cond)`:阻塞当前进程,释放管程互斥锁
|
||||
- `signal(cond)`:唤醒一个在 `cond` 上等待的进程(如果存在)
|
||||
- **MESA 管程**(实际OS采用):`signal` 只是将等待进程移入就绪队列,需用 `while` 重新检查条件
|
||||
|
||||
---
|
||||
|
||||
### 要点 10 - 死锁的条件与预防
|
||||
|
||||
#### 死锁定义
|
||||
|
||||
多个进程因竞争资源而造成的一种互相等待的僵局。
|
||||
|
||||
#### 四个必要条件(必须同时满足)
|
||||
|
||||
| 条件 | 说明 |
|
||||
|------|------|
|
||||
| **互斥** | 资源一次只能被一个进程占用 |
|
||||
| **请求与保持** | 进程已持有资源,又请求新资源,但不释放已有资源 |
|
||||
| **不可剥夺** | 进程已获得的资源不能被强制剥夺 |
|
||||
| **循环等待** | 存在进程资源的循环等待链 |
|
||||
|
||||
#### 死锁预防
|
||||
|
||||
| 策略 | 破坏的条件 | 缺点 |
|
||||
|------|-----------|------|
|
||||
| **互斥突破** | 互斥 | 许多资源本身就是互斥的,不可行 |
|
||||
| **请求与保持突破** | 请求与保持 | 资源利用率低,可能饥饿 |
|
||||
| **不可剥夺突破** | 不可剥夺 | 实现复杂,加重系统开销 |
|
||||
| **循环等待突破** | 循环等待 | 资源编号顺序申请,增加编程复杂度 |
|
||||
|
||||
---
|
||||
|
||||
### 要点 11 - 银行家算法
|
||||
|
||||
#### 数据结构
|
||||
|
||||
- `Available[m]`:每种资源的可用数量
|
||||
- `Max[n][m]`:每个进程对每种资源的最大需求
|
||||
- `Allocation[n][m]`:每个进程已分配的资源数
|
||||
- `Need[n][m]`:每个进程还需要的资源数,`Need = Max - Allocation`
|
||||
|
||||
#### 安全性算法
|
||||
|
||||
1. 设 `Work = Available`,`Finish[i] = false`
|
||||
2. 寻找 `Finish[i] = false` 且 `Need[i] <= Work` 的进程
|
||||
3. 若找到,则 `Work += Allocation[i]`,`Finish[i] = true`,重复步骤2
|
||||
4. 若所有 `Finish[i] = true`,则系统安全
|
||||
|
||||
#### 资源请求算法
|
||||
|
||||
1. 若 `Request[i] > Need[i]`,则出错
|
||||
2. 若 `Request[i] > Available`,则等待
|
||||
3. 尝试分配:`Available -= Request[i]`,`Allocation[i] += Request[i]`,`Need[i] -= Request[i]`
|
||||
4. 执行安全性算法,若安全则正式分配,否则回滚并等待
|
||||
|
||||
---
|
||||
|
||||
### 要点 12 - 死锁检测与恢复
|
||||
|
||||
#### 检测方法
|
||||
|
||||
通过**资源分配图**(Resource Allocation Graph)检测循环等待。
|
||||
|
||||
**资源分配图简化**:
|
||||
- 找出非阻塞非孤立的进程(能获得全部所需资源)
|
||||
- 消去其所有请求边和分配边
|
||||
- 若能消去所有边,则无死锁
|
||||
|
||||
#### 恢复方法
|
||||
|
||||
- **剥夺资源**:从死锁进程剥夺资源给其他进程
|
||||
- **终止进程**:终止所有死锁进程或逐个终止直到解除死锁
|
||||
- **进程回退**:回退到安全状态(需要系统支持)
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
# 操作系统笔记导航
|
||||
|
||||
## 要点索引
|
||||
|
||||
### [01_进程管理.md](./01_进程管理.md)
|
||||
|
||||
### [02_CPU调度.md](./02_CPU调度.md)
|
||||
|
||||
### [03_同步互斥与死锁.md](./03_同步互斥与死锁.md)
|
||||
- [要点 01 - 临界区与互斥基本概念](./03_同步互斥与死锁.md#要点-01---临界区与互斥基本概念)
|
||||
- [要点 02 - Peterson 算法](./03_同步互斥与死锁.md#要点-02---Peterson-算法)
|
||||
- [要点 03 - 硬件互斥方法](./03_同步互斥与死锁.md#要点-03---硬件互斥方法)
|
||||
- [要点 04 - 信号量机制](./03_同步互斥与死锁.md#要点-04---信号量机制)
|
||||
- [要点 05 - 生产者-消费者问题](./03_同步互斥与死锁.md#要点-05---生产者-消费者问题)
|
||||
- [要点 06 - 读者-写者问题](./03_同步互斥与死锁.md#要点-06---读者-写者问题)
|
||||
- [要点 07 - 哲学家就餐问题](./03_同步互斥与死锁.md#要点-07---哲学家就餐问题)
|
||||
- [要点 08 - 吸烟者问题](./03_同步互斥与死锁.md#要点-08---吸烟者问题)
|
||||
- [要点 09 - 管程](./03_同步互斥与死锁.md#要点-09---管程)
|
||||
- [要点 10 - 死锁的条件与预防](./03_同步互斥与死锁.md#要点-10---死锁的条件与预防)
|
||||
- [要点 11 - 银行家算法](./03_同步互斥与死锁.md#要点-11---银行家算法)
|
||||
- [要点 12 - 死锁检测与恢复](./03_同步互斥与死锁.md#要点-12---死锁检测与恢复)
|
||||
|
||||
---
|
||||
|
||||
## 快速跳转
|
||||
|
||||
| 章节 | 主题 | 要点数 |
|
||||
|------|------|--------|
|
||||
| 01 进程管理 | 进程组成、状态、线程 | - |
|
||||
| 02 CPU调度 | 调度算法 | - |
|
||||
| 03 同步互斥与死锁 | 互斥、同步、经典问题、死锁 | 12 |
|
||||
|
||||
**参考教材**:《计算机操作系统》汤子瀛、《Operating System Concepts》Silberschatz
|
||||
Loading…
Reference in New Issue