进程同步互斥
重点 生产者 - 消费者问题
问题描述
- 生产者:生产数据放入缓冲区
- 消费者:从缓冲区取数据消费
- 同步关系:缓冲区满则生产者等待,缓冲区空则消费者等待
- 互斥关系:对缓冲区的互斥访问
PV 解决方案(3 个信号量)
semaphore mutex = 1; // 保护缓冲区互斥访问
semaphore empty = N; // 空缓冲区数量
semaphore full = 0; // 满缓冲区数量
// 生产者
while (true) {
produce(data);
P(empty); // 先申请空缓冲区(资源信号量)
P(mutex); // 再申请互斥访问
put(data);
V(mutex);
V(full); // 满缓冲区 +1
}
// 消费者
while (true) {
P(full);
P(mutex);
get(data);
V(mutex);
V(empty);
consume(data);
}
P 操作顺序
- 必须先 P(资源信号量),再 P(互斥信号量)
- 如果顺序颠倒(先 P(mutex) 再 P(empty)),满缓冲区时生产者持有 mutex 阻塞,消费者无法进入,形成死锁
重点 读者 - 写者问题
读者优先
- 多个读者可同时读
- 写者必须独占访问,且只能等所有读者完成
- 使用
readcount 统计读者数,mutex 保护 readcount,wrt 实现写者互斥
semaphore mutex = 1;
semaphore wrt = 1;
int readcount = 0;
// 读者
P(mutex);
readcount++;
if (readcount == 1) P(wrt); // 第一个读者锁住写者
V(mutex);
read;
P(mutex);
readcount--;
if (readcount == 0) V(wrt); // 最后一个读者释放写者
V(mutex);
// 写者
P(wrt);
write;
V(wrt);
写者优先
- 当有写者等待时,新读者不能开始读
- 需额外的信号量
read 来阻塞新读者
重点 哲学家就餐问题
问题描述
- 5 个哲学家围坐,5 支筷子交替放置
- 每个哲学家需要两支筷子才能进餐
- 死锁风险:所有哲学家同时拿起左边筷子,导致循环等待
解决方案
- 限制并发人数:最多只允许 4 个哲学家同时就餐(信号量
limit = 4)
- 奇偶拿筷:奇数号先取左边筷子,偶数号先取右边筷子,打破循环等待
- AND 信号量:同时申请两支筷子(一次 P 操作获取全部所需资源)
重点 管程(Monitor)
- 将共享数据和对该数据的操作封装在一起
- 类似 OOP 中的类:共享变量 + 方法 + 条件变量
- 同一时间只有一个进程能进入管程,自动保证互斥
- 使用条件变量(Condition Variable)实现同步
信号量解决思路总结
- 互斥信号量 mutex 保护临界区
- 资源信号量 empty/full 表示缓冲区状态
- 同步信号量协调执行顺序