首页/操作系统/02-process/生产者消费者问题详解 🔗 在 Obsidian 中打开
操作系统 · 02-process

生产者消费者问题详解

重要度 ★★ 生产者消费者信号量缓冲区死锁
速查
一组生产者与消费者共享大小为 $n$ 的有界缓冲区。需要三个信号量:mutex=1(互斥)、empty=n(空位)、full=0(产品数)。必须先 P(同步) 再 P(mutex),否则死锁。

速查

一组生产者进程和一组消费者进程共享一个大小为 $n$ 的有界缓冲区:

  • 生产者:生产产品放入缓冲区,缓冲区满时等待
  • 消费者:从缓冲区取产品消费,缓冲区空时等待
  • 缓冲区是临界资源,同一时刻只能一个进程访问
信号量初值含义
mutex1互斥信号量,保证缓冲区互斥访问
emptyn同步信号量,空缓冲区数量
full0同步信号量,满缓冲区数量(已有产品数)

核心概念

PV 操作顺序(关键)

生产者:                消费者:
生产一个产品             P(full)      // 申请产品(同步)
P(empty)     // 同步    P(mutex)     // 互斥
P(mutex)     // 互斥    取出产品
放入产品                 V(mutex)     // 释放
V(mutex)     // 释放    V(empty)     // 通知空位
V(full)      // 通知   消费产品
顺序重要性 必须先 P(同步信号量),再 P(mutex)!
  • 若先 P(mutex) 再 P(empty):缓冲区满时,生产者持有 mutex 等 empty,消费者需 mutex 才能取产品释放 empty → 死锁
  • 若先 P(mutex) 再 P(full):缓冲区空时,消费者持有 mutex 等 full,生产者需 mutex 才能放产品释放 full → 死锁
V 操作顺序无所谓(V 不会阻塞),但习惯先 V(mutex) 再 V(同步)。

手算示例

例:$n=3$ 缓冲区,初始 $empty=3, full=0, mutex=1$。生产者放一个产品 A:

步骤操作emptyfullmutex缓冲区
1生产者 P(empty)201[]
2生产者 P(mutex)200[]
3放入产品 A200[A]
4生产者 V(mutex)201[A]
5生产者 V(full)211[A]

死锁场景($n=1$,生产者先 P(mutex) 再 P(empty))

步骤操作emptyfullmutex状态
1生产者 P(mutex)100获得锁
2生产者放入产品100缓冲区满
3生产者再 P(empty)000阻塞
4消费者 P(full)000阻塞
生产者等 empty,消费者等 mutex死锁

易错点

注意
  • 必须先 P(同步) 再 P(mutex),顺序颠倒可能死锁
  • V 操作顺序无硬性要求,因 V 不阻塞
  • 多个生产者/消费者时,mutex 仍为 1(只管缓冲区互斥)
  • empty/full 初值取决于缓冲区大小,与进程数无关

核心结论

必背
  1. 需要 3 个信号量:mutex=1、empty=n、full=0
  2. 先 P(同步) 再 P(mutex),否则死锁
  3. V(mutex) 后再 V(同步),让其他进程尽快进临界区
  4. mutex 始终为 1,与生产者/消费者数量无关

记忆卡片

需要几个信号量?
3 个:mutex=1(互斥)、empty=n(空位)、full=0(产品数)。
为何先 P(同步) 再 P(mutex)?
反过来死锁:生产者先持 mutex 等 empty,消费者需 mutex 才能释放 empty。
V 操作顺序有要求吗?
无硬性要求,V 不阻塞;习惯先 V(mutex) 再 V(同步)。
多生产者时 mutex 仍为 1?
是。mutex 只保证缓冲区互斥,与进程数无关。
变体有哪些?
多类产品、单缓冲区、生产者间互斥、读者-写者同类问题。

交互动画 · 缓冲区与死锁演示

有界缓冲区(n=3) 信号量
点击「生产者放一个」「消费者取一个」观察缓冲区与信号量变化;「死锁演示」展示错误顺序
empty/full 同步信号量;mutex=1 互斥。先 P(同步) 再 P(mutex)

相关知识点

readers-writers dining-philosophers process-synchronization-semaphore monitor

↑ 以上为站内 HTML 相对链接(纯网页可浏览);本页右上「在 Obsidian 中打开」跳回源笔记。