操作系统同步互斥问题
一些经典的例子就不列举了,接下来讲一些在学习操作系统课程的过程中所遇到的几个进程同步的题目。
1.取放水果问题
用基本记录型信号量解决如下同步关系:一空盘放一水果,父放梨,母放橘,儿取梨,女取橘,四人如何并发?由题目我们可以知道缓冲区只有一个,父母放水果之间及儿女取水果之间是互斥的关系,而且父放了梨之后儿子才能取梨,母亲放了橘子后女儿才能取橘子。站着资源的角度上,我们要定义三个信号量,empty:表示空盘,pear:表示梨子,orange:表示橘子。以下是伪代码:
seamphore empty=1,pear=0,orange=0;//最开始是有一个空,还没有放橘子和梨;
//父亲
threadAddF(){
wait(empty);
···
放梨;
···
signal(peal);
}
//母亲
threadAddM(){
wait(empty);
···
放橘子;
···
signal(orange);
}
//儿子
threadAddS(){
wait(pear);
···
取梨;
···
signal(empty);
}
//女儿
threadAddF(){
wait(orange);
···
取橘子;
···
signal(empty);
}
//主函数
void main(){
threadAddF();
threadAddM();
threadAddS();
threadAddD();
}
这个例子比较简单,也很好理解。
2.黑白棋子问题
大家对于下棋肯定不陌生,这里列举两种情况:
黑子先下;
谁先抢到谁先下。第一种情况:黑子先下时
seamphore bfg=1,wfg=0;//bfg表示控制黑棋的信号量,wfg控制白棋;
//黑棋
void black(){
while(true){
wait(bfg);
if(在棋盘上找到位置){
signal(wfg);
下一枚黑棋子;
}
else{
signal(wfg);
break;
}
}
}
//白棋
void white(){
while(true){
wait(wfg);
if(在棋盘上找到位置){
signal(bfg);
下一枚白棋子;
}
else{
signal(bfg);
break;
}
}
}
//主函数
void main(){
black();
white();
}
情况二:抢占先机,谁先抢到谁先下。当然这只是对于第一枚棋子谁先下的问题。
seamphore bfg=0,wfg=0,m=1;
boolean fg=false;
//黑棋
void black(){
wait(m);//m控制黑白棋之间的互斥;
if(!fg){
bfg=1;
wfg=0;
fg=true;
}
while(true){
wait(bfg);
if(在棋盘上找到位置){
signal(wfg);
下一枚黑棋子;
}
else{
signal(wfg);
break;
}
}
siganl(m);
}
//白棋
void black(){
wait(m);//m控制黑白棋之间的互斥;
if(!fg){
bfg=0;
wfg=1;
fg=true;
}
while(true){
wait(wfg);
if(在棋盘上找到位置){
signal(bfg);
下一枚黑棋子;
}
else{
signal(bfg);
break;
}
}
siganl(m);
}
为什么第二种情况要定义m呢?
我们都知道进程之间是并发执行的,那么假设一种情况:没有定义m,黑白棋程序同时执行(因为是同时执行,那么fg都还是初始值false),同时进入if语句,那么对于黑棋来说,bfg=1,wfg=0;对于白棋,wfg=1,bfg=0;双方都可以进行下棋的操作,这就违背了黑白棋之间的互斥规则,所以必须要定义一个信号量m,来控制黑白棋的互斥。
3.新加条件的生产者消费者问题
多个生产者和消费者,共享一个能存放n个产品的环形缓冲区(初始为空)。缓存区未满生产者可以放入一个产品,否则等待,缓冲区没空则消费者可以取一个产品,否则等待。要求每个消费者连续取10件产品才能让其他消费者取。
buffer: array [ 0, …, n-1] of item;
in, out,i: integer :=0, 0,1;
//不使用Counter变量,而是用信号量
Var mutex, empty, full,cm: semaphore :=1, n, 0,1;//empty和full分别表示缓冲池中空缓冲池和满缓冲池(即产品)的数量
//生产者
producer :
repeat
…
produce an item in nexp;
…
wait(empty);
wait(mutex);
buffer(in):=nexp;
in:=(in+1) mod n;
signal(mutex);
signal(full);
until false;
//消费者
consumer:
repeat
wait(cm);//cm控制消费者之间的互斥;
for(i=1;i<=10;i++){
wait(full);
wait(mutex);
buffer(out):=nexp;
out:=(out+1) mod n;
signal(mutex);
signal(empty);
}
signal(cm);
consume an item in nexp;
until false;
4. 工人装水问题
两个搬运工人向卡车中装纯净水,每车最多20箱。卡车装满即开走,需装10辆车。
两个工人的情况不太好理解,所以我们先来讨论一个工人的情况:
Var mutex, empty, go: semaphore :=1, 0,0;//empty表示卡车内的水箱
i,count: integer :=1,0;
//卡车
void truck(){
wait(mutex);//mutex控制车位上的互斥;
...
进入装水位;
...
for(i=1;i<=20;i++)
signal(empty);
wait(go);//go控制卡车离开
离开;
signal(mutex);
}
//工人
void worker(){
while(true){
wait(empty);
...
装水;
...
count++;
if(count==20){
signal(go);
count=0;
}
}
}
//主函数
void main(){
for(i=1;i<=10;i++){
truck();
worker();
}
}
两个工人的情况:主要是对count的控制
增加一个信号量cm,初值为1;
主函数和truck()不变,worker()如下:
void worker(){
while(true){
wait(empty);
...
装水;
...
wait(cm);//cm控制工人间的互斥
count++;
if(count==20){
signal(go);
count=0;
signal(cm);
}
}
}