一组生产者进程和一组消费者进程共享一个大小为 $n$ 的有界缓冲区:
| 信号量 | 初值 | 含义 |
|---|---|---|
mutex | 1 | 互斥信号量,保证缓冲区互斥访问 |
empty | n | 同步信号量,空缓冲区数量 |
full | 0 | 同步信号量,满缓冲区数量(已有产品数) |
PV 操作顺序(关键):
生产者: 消费者:
生产一个产品 P(full) // 申请产品(同步)
P(empty) // 同步 P(mutex) // 互斥
P(mutex) // 互斥 取出产品
放入产品 V(mutex) // 释放
V(mutex) // 释放 V(empty) // 通知空位
V(full) // 通知 消费产品
例:$n=3$ 缓冲区,初始 $empty=3, full=0, mutex=1$。生产者放一个产品 A:
| 步骤 | 操作 | empty | full | mutex | 缓冲区 |
|---|---|---|---|---|---|
| 1 | 生产者 P(empty) | 2 | 0 | 1 | [] |
| 2 | 生产者 P(mutex) | 2 | 0 | 0 | [] |
| 3 | 放入产品 A | 2 | 0 | 0 | [A] |
| 4 | 生产者 V(mutex) | 2 | 0 | 1 | [A] |
| 5 | 生产者 V(full) | 2 | 1 | 1 | [A] |
死锁场景($n=1$,生产者先 P(mutex) 再 P(empty)):
| 步骤 | 操作 | empty | full | mutex | 状态 |
|---|---|---|---|---|---|
| 1 | 生产者 P(mutex) | 1 | 0 | 0 | 获得锁 |
| 2 | 生产者放入产品 | 1 | 0 | 0 | 缓冲区满 |
| 3 | 生产者再 P(empty) | 0 | 0 | 0 | 阻塞 |
| 4 | 消费者 P(full) | 0 | 0 | 0 | 阻塞 |
| — | 生产者等 empty,消费者等 mutex | — | — | — | 死锁 |
mutex=1(互斥)、empty=n(空位)、full=0(产品数)。↑ 以上为站内 HTML 相对链接(纯网页可浏览);本页右上「在 Obsidian 中打开」跳回源笔记。