26-OS-PV大题
生产消费者
六步骤:
一、明确进程分类
确定有几类进程,每类进程对应一个函数 ,清晰区分不同角色(如生产者、消费者,或案例里的 “同学、大师傅” )。
二、描述进程动作
在进程函数内部,用中文描述核心行为:
- 若动作 “只做一次”,不加
while(1)
循环; - 若动作 “不断重复”,用
while(1)
包裹逻辑。
三、分析 PV 操作
梳理进程动作前是否需P
操作(申请资源 / 锁):
- 只要用
P
(申请),必须配对V
(释放),保证资源 / 信号量正确回收; - 注意 “隐含互斥”,比如操作临界资源(共享变量、设备),需加
P(mutex)
等互斥信号量。
四、定义信号量
所有P
/V
逻辑写完后,再定义信号量(如Semaphore
类型),并确定初始值:
- 需结合资源初始状态(如 “rice=0 、 one=100” ,根据生产 / 消费逻辑设置 )。
五、检查死锁风险
重点看连续P
操作:
- 若多个
P
连续出现,尝试调整顺序,避免循环等待; - 若某信号量
P
/V
“连续且无其他P
插入”,因不破坏 “请求和保持”,一般不会死锁。
六、验证题目要求
最后读题复盘:确认进程逻辑、PV 配对、资源交互是否贴合题目场景(如生产消费流程、资源数量约束等 ),保证模型满足需求。
核心逻辑:通过 “分类→动作→PV→信号量→死锁→验证” 六步,逐步搭建进程同步模型,用 PV 操作解决 “生产 - 消费” 的资源协调问题,同时规避死锁风险 。
同步问题和生产消费同时完成:
定义五类:
// 进程A:独立执行,完成后释放信号量通知后续进程
A() {操作A; // 进程A的核心任务(无前置依赖)V(A完成); // A执行完毕,释放" A完成 "信号量(值+1)
}// 进程B:独立执行,完成后释放信号量通知后续进程
B() {操作B; // 进程B的核心任务(无前置依赖)V(B完成); // B执行完毕,释放" B完成 "信号量(值+1)
}// 进程C:依赖A和B完成后才能执行
C() {P(A完成); // 等待A执行完毕(若A未完成则阻塞)P(B完成); // 等待B执行完毕(若B未完成则阻塞)操作C; // 只有A和B都完成后,才能执行C的任务V(C完成); // C执行完毕,释放" C完成 "信号量(值+1)
}// 进程D:独立执行,完成后释放信号量通知后续进程
D() {操作D; // 进程D的核心任务(无前置依赖)V(D完成); // D执行完毕,释放" D完成 "信号量(值+1)
}// 进程E:依赖C和D完成后才能执行
E() {P(C完成); // 等待C执行完毕(若C未完成则阻塞)P(D完成); // 等待D执行完毕(若D未完成则阻塞)操作E; // 只有C和D都完成后,才能执行E的任务
}
哲学家进餐(只有一种资源才能运行)
操作模板:使用int变量表示资源
// 定义互斥大锁(用于资源操作的同步)
semaphore Lock = 1; // 定义各类资源的剩余数量
int a = 9; // 资源a剩余数量
int b = 8; // 资源b剩余数量
int c = 5; // 资源c剩余数量Process() {while(1) {P(Lock); // 申请锁,进入临界区// 检查所需资源是否充足if(所有资源都满足需求) {// 按需求减少对应资源的剩余数量各类资源int--; // 具体减少数量根据题目要求确定// 一次性获取所有所需资源取对应资源;V(Lock); // 释放锁,退出临界区break; // 成功获取资源,跳出循环}V(Lock); // 资源不足,释放锁,等待下次尝试}// 执行进程的核心任务(例如:哲学家进餐)做进程该做的事;P(Lock); // 申请锁,进入临界区// 一次性归还所有资源,恢复资源剩余数量各类资源int++; // 归还数量与之前获取的数量一致V(Lock); // 释放锁,退出临界区
}