可以用以下的思考步骤来完成这类问题:
- 有几类进程?每一类进程会对应一个函数
- 如何描述进程内的动作(执行内容)?考虑是否循环等
- 在每个执行步骤是否需要P?注意:有P必考虑在何处V
- 定义信号量
- 检查多个P连续操作?确定是否死锁
在该类问题中死锁的情况基本只有请求和保持
解决方法:1. PV连续出现,不可能死锁;2.多个P死锁,则尝试调整P操作的顺序
例一
- 三类进程:生产A、生产B、装配A+B
p1() {} // 生产A
p2() {} // 生产B
cs() {} // 装配A+B
- 确定各个进程的操作:一定要细致,每一步都要写上
- p1:生产A,送到F1
- p2:生产B,送到F2
- cs:从F1取一个A,从F2取一个B,组装A+B
- 是否需要循环?要
p1() {
while(1){
生产A
送到F
}
} // 生产A
p2() {
while(1){
生产B
送到F2
}
} // 生产B
cs() {
while(1){
从F1取一个A
从F2取一个B
组装A+B
}
} // 装配A+B
- 确定互斥情况⭐
- 对P1:生产A之前,不需要;装到F1需要,F1相当于缓冲区,容量为10
- 对P2:与P1同理
- 对cs:取A/B之前判断是否F1/F2有,组装不需要互斥
p1() {
while(1){
生产A
P(F1)
送到F1
}
} // 生产A
p2() {
while(1){
生产B
P(F1)
送到F2
}
} // 生产B
cs() {
while(1){
P(full1)
从F1取一个A
P(full2)
从F2取一个B
组装A+B
}
} // 装配A+B
这里就有很大的问题,还是那个道理,有P必V,建议就是做出一个P,先找在何处V,再去进行下一个PV的操作,这样就不容易出现缺漏
p1() {
while(1){
生产A
P(F1)
送到F1
V(full1) // 在cs中P(full1),当放入一个时,则需要V(full1)
}
} // 生产A
p2() {
while(1){
生产B
P(F1)
送到F2
V(full1) // 在cs中P(full2),当放入一个时,则需要V(full)
}
} // 生产B
cs() {
while(1){
P(full1)
从F1取一个A
V(F1) // 在P1中P(F1),当取出一个时,则需要V(F1)
P(full2)
从F2取一个B
V(F1) // 在P2中P(F2),当取出一个时,则需要V(F2)
组装A+B
}
} // 装配A+B
- 定义信号量(就是简单的命名和美化、设置初始值)
semaphore F1 = 10 // 表示F1货架的剩余容量
semaphore F2 = 10 // 表示F2货架的剩余容量
semaphore full1 = 0 // 表示F1货架上A产品
semaphore full1 = 0 // 表示F2货架上B产品
- 最后这一步也是最容易被遗忘的一步,检查死锁问题和互斥资源访问
这里不会产生死锁,但是货架的访问应为互斥,因此增加对货架的PV操作
p1() {
while(1){
生产A
P(F1)
P(metux1)
送到F1
V(metux1)
V(full1)
}
} // 生产A
p2() {
while(1){
生产B
P(F1)
P(metux2)
送到F2
V(metux2)
V(full1)
}
} // 生产B
cs() {
while(1){
P(full1)
P(metux1)
从F1取一个A
V(metux1)
V(F1)
P(full2)
P(metux2)
从F2取一个B
V(metux2)
V(F1)
组装A+B
}
} // 装配A+B
最后的答案(多加了一个判断货架是否有产品)
小试牛刀
解答:
- 两类进程:小和尚和老和尚;
- 执行内容:小和尚抬水入缸,老和尚饮水,循环
- 需要互斥的资源:桶、水井、缸
producer() { // 注释中的序号并不表示执行顺序,只表示一组PV操作的对应
while(1) {
p(tong) // 1
p(jing) // 2(同一时间只有一个桶能取水)
桶取水
v(jing) // 2
p(empty) // 3(缸的容量有限)
p(gang) // 4(同一时间只有一个桶能倒水入缸)
桶入缸
v(gang) // 4
v(full) // 6(入缸后增加了缸里的水)
v(tong) // 1
}
}
consumer() {
while(10 {
p(tong) // 5
p(full) // 6(表示缸里还有多少水)
p(gang) //7
入缸取一桶水
v(gang) //7
v(empty) // 3
喝水
v(tong) // 5
}
}
上述解答会产生死锁:若桶都被consumer拿走,但是缸中无水,此时producer也无法打水,程序死锁
producer() { // 注释中的序号并不表示执行顺序,只表示一组PV操作的对应
while(1) {
p(empty) // 3(缸的容量有限,有空位才提桶)
p(tong) // 1
p(jing) // 2(同一时间只有一个桶能取水)
桶取水
v(jing) // 2
p(gang) // 4(同一时间只有一个桶能倒水入缸)
桶入缸
v(gang) // 4
v(full) // 6(入缸后增加了缸里的水)
v(tong) // 1
}
}
consumer() {
while(10 {
p(full) // 6(表示缸里还有多少水,有水才提桶)
p(tong) // 5
p(gang) //7
入缸取一桶水
v(gang) //7
v(empty) // 3
喝水
v(tong) // 5
}
}