写在前面
一般该类型题就是让你自定义几个同步信号量和互斥信号量,然后让你以PV原语的形式加到几个程序段中,其中最重要的就是这个信号量的定义,以及初始值应该为多少。
互斥信号量
互斥信号量比较容易看出来,一般是表示同一个资源只能同时被一个东西访问的时候采用互斥信号量,默认初始值为1。
同步信号量
重难点!
一般是表示资源的个数,可能大家做题的时候会发现有初始值为0的,有初始值为其他数字的,甚至还有一个东西非得定义一个empty和full两个信号量的。而且最要命的是同步信号量很容易漏掉某一个,导致整个题0分,下面是我个人总结的一些思路,最后面有例题。
题干分析
- 首先好好读一遍题,先看看哪些资源同时只能被一个用户访问,比如“某个盘子每次只能放一个苹果”或者“一口井每次只能放进去一个桶”,注意这样的字眼。
- 根据上面观察到的定义互斥信号量,注意,互斥信号量可能不止一个,存在多个也不意外,注意读题就行。
- 接下来是重点,对同步信号量的定义。
- 首先要知道需要定义几个同步信号量,然后再确定他们的值。
- 确定同步信号量个数需要分析有几个事件会造成进程堵塞(本篇文章最重要的一句话,请仔细思考,不明白的请看例题)
- 之后就是确定同步信号量的值,为事件刚开始发生时所有信号的初值(请仔细思考,不明白的请看例题)
- 最后是将信号量的PV原语填进程序段中
- 先填互斥信号量,一般紧挨着互斥区
- 之后填同步信号量,只需要理解P操作消耗资源,可能会引起进程阻塞;V操作释放资源,可能会引起进程就绪
- 最后检查一下多个P操作相邻的地方,这个地方如果P操作顺序不当可能会引起死锁
例题讲解
分析&读题
- 本题中的桶小和尚和老和尚都会用,且信号量较多,是较复杂的一道题
- 首先看一下互斥信号量的个数:“每次只能容一个桶从井里取水”,“每次入缸取水仅为一桶水,且不可同时进行” ,存在两个信号量,我们分别定义为mutex1=1,mutex2=1。
- 接下来是重点:同步信号量的个数。还记得我们上面的方法吗,找到可能会引起进程阻塞的事件的个数(嘿嘿,这个方法我见网上都没有,是我自己想出来的,喜欢的同学可以点赞加收藏)
- 当水缸空的时候,老和尚不能取水,阻塞。(设置信号量empty表示水缸空)
- 当水缸空的时候,老和尚不能取水,阻塞。(设置信号量empty表示水缸空位置)
- 当水缸满的时候,小和尚不能加水,阻塞(设置信号量full表示水缸满时总容纳水桶数量)
- 似乎没有其他的阻塞事件了
- 然后是设置信号量的初始值。 当事件还没发生时,即小和尚没挑水,老和尚没取水时,empty为10,full为0 。因为此时由10个空位置对吧。桶在事件发生前有三个,初始值设置为3.
- 此时我们总结一下我们上面读题和分析的结果:
- semaphore mutex1=1;
- semaphore mutex2=1;
- semaphore empty=10;
- semaphore full=0;
- semaphore budget=3;
- 之后我们看一下两个线程的程序结构:
Process Old{
从缸里取水
喝水
}
Process Young{
从水井取水
倒进缸里
}
- 首先我们添加互斥信号量
从上面我们的互斥信号量定义可以看出,从井里 (mutex1) 取水需要加互斥信号量,从缸里(mutex2)取水也需要加互斥信号量。
Process Old{
P(mutex2) *
从缸里取水
V(mutex2) *
喝水
}
Process Young{
P(mutex1) *
从水井取水
V(mutex1) *
P(mutex2) *
倒进缸里
V(mutex2) *
}
- 添加同步信号量
已知上面三种阻塞对应三种同步信号量,我们根据阻塞出发
- 当水缸空的时候,老和尚不能取水,阻塞。(设置信号量empty表示水缸空位置)
- 当水缸满的时候,小和尚不能加水,阻塞(设置信号量full表示水缸满时总容纳水桶数量)
- 水桶被用完的时候,小和尚和老和尚都阻塞(设置信号量budget表示水桶个数)
水缸空
Process Old{
P(full) *
P(mutex2)
从缸里取水
V(mutex2)
喝水
}
Process Young{
P(mutex1)
从水井取水
V(mutex1)
P(mutex2)
倒进缸里
V(mutex2)
V(full) *
}
水缸满
Process Old{
P(full)
P(mutex2)
从缸里取水
V(mutex2)
V(empty) *
喝水
}
Process Young{
P(empty) *
P(mutex1)
从水井取水
V(mutex1)
P(mutex2)
倒进缸里
V(mutex2)
V(full)
}
水桶被用完
Process Old{
P(full)
P(budget) *
P(mutex2)
从缸里取水
V(mutex2)
V(empty)
喝水
V(budget) *
}
Process Young{
P(empty)
P(budget) *
P(mutex1)
从水井取水
V(mutex1)
P(mutex2)
倒进缸里
V(mutex2)
V(budget) *
V(full)
}
- 观察是否有死锁
- 观察两个程序连续P操作的地方,无问题
- 注意,连续V操作的顺序可改变,不影响进程运行
没看明白的多看几遍,自己推推,看明白的点赞收藏