PV操作题目

PV操作核心大题(生产者-消费者模型:水缸取水/倒水问题)

一、题目场景

某寺庙存在若干小和尚和老和尚,水井水量无限,水缸最大容量为12桶;水桶总数固定为N个,且满足以下约束:

  1. 水井同一时间仅允许1个小和尚打水;

  2. 水缸同一时间仅允许1个和尚(小/老)执行倒水/取水操作;

  3. 小和尚仅能在水缸未满时打水倒入,老和尚仅能在水缸有水时取水;

  4. 避免水桶被全部占用导致死锁(如老和尚空拿桶等水,小和尚无桶可用)。

请基于PV操作设计小和尚(打水倒水)和老和尚(取水)的进程逻辑,并说明各信号量的含义。

二、信号量定义(核心:信号量=进程执行某操作的“凭证”)

信号量名称 初始值 作为“执行凭证”的核心含义
empty 12 小和尚的“倒水资格凭证”:表示水缸剩余可倒入的桶数,持有该凭证才能启动“打水倒入水缸”流程(P操作=消耗凭证,剩余容量-1)
full 0 老和尚的“取水资格凭证”:表示水缸中已有的水量桶数,持有该凭证才能启动“从水缸取水”流程(P操作=消耗凭证,已有水量-1)
pail N 所有和尚的“用桶资格凭证”:表示当前可用水桶数量,持有该凭证才能拿桶(P=消耗,V=归还)
mutex_well 1 小和尚的“水井独占凭证”:互斥信号量,持有该凭证才能独占水井打水(保证水井操作原子性)
mutex_wat 1 所有和尚的“水缸独占凭证”:互斥信号量,持有该凭证才能独占水缸操作(倒水/取水,保证水缸操作原子性)

三、PV操作实现(408标准答题伪代码)

1. 小和尚进程(生产者:打水→倒入水缸)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void xiao_heshang() {
while(true) { // 循环执行打水操作
P(empty); // 消耗“倒水资格”:确认水缸有剩余容量,否则等待
P(pail); // 消耗“用桶资格”:拿取可用水桶,否则等待
P(mutex_well); // 消耗“水井独占资格”:独占水井
从水井打一桶水; // 临界区:水井操作(仅当前小和尚执行)
V(mutex_well); // 释放“水井独占资格”:归还水井使用权
P(mutex_wat); // 消耗“水缸独占资格”:独占水缸
将水倒入水缸; // 临界区:水缸倒水(仅当前小和尚执行)
V(mutex_wat); // 释放“水缸独占资格”:归还水缸使用权
V(pail); // 释放“用桶资格”:归还水桶
V(full); // 释放“取水资格”:水缸水量+1,给老和尚提供取水凭证
}
}
2. 老和尚进程(消费者:从水缸取水)
1
2
3
4
5
6
7
8
9
10
11
void lao_heshang() {
while(true) { // 循环执行取水操作
P(full); // 消耗“取水资格”:确认水缸有水,否则等待
P(pail); // 消耗“用桶资格”:拿取可用水桶,否则等待
P(mutex_wat); // 消耗“水缸独占资格”:独占水缸
从水缸取出一桶水; // 临界区:水缸取水(仅当前老和尚执行)
V(mutex_wat); // 释放“水缸独占资格”:归还水缸使用权
V(pail); // 释放“用桶资格”:归还水桶
V(empty); // 释放“倒水资格”:水缸剩余容量+1,给小和尚提供倒水凭证
}
}

四、408高频提问与核心解析

  1. 为何emptyfull不能合并为一个信号量?
    合并后无法同时约束“水缸不溢出”(小和尚的倒水前提)和“水桶死锁”(老和尚空拿桶):

    • empty仅约束小和尚的“倒水资格”,确保水缸未满才会启动打水;
    • full仅约束老和尚的“取水资格”,确保有水才会抢占水桶,避免水桶被无效占用。
  2. 老和尚进程中P(full)必须在P(pail)之前的原因?
    若先P(pail)P(full):可能出现所有老和尚抢占完所有水桶,等待full(水缸无水),导致小和尚无桶可用,触发死锁;调整顺序后,只有“有取水资格”的老和尚才会抢占水桶,从根源避免死锁。

  3. mutex_well/mutex_watempty/full的本质区别?

    • mutex_*互斥凭证:保证单个资源(水井/水缸)的临界区操作原子性,初始值恒为1;
    • empty/full同步凭证:约束生产者(小和尚)和消费者(老和尚)的执行顺序,初始值由资源总量(水缸容量)决定。

总结

  1. 信号量的“凭证属性”:同步信号量(empty/full)是“执行前置条件的凭证”,互斥信号量(mutex_*)是“独占资源的凭证”;

  2. 顺序原则:同步P操作(P(full)/P(empty))必须在互斥P操作(P(pail)/P(mutex_*))之前,避免死锁;

  3. 生产者-消费者模型核心:有容量上限的共享容器(如水缸),需用一对同步信号量(empty/full)分别约束生产者和消费者,再用互斥信号量保证容器操作的原子性。