操作系统笔记——生产者消费者问题

2,432 阅读6分钟

一、生产者--消费者问题

类型1

1.问题描述

系统中的进程:n个生产者,m个消费者共享k个缓冲区

2.问题分析

(1)互斥:缓冲池
(2)同步:缓冲池未满,生产者可将消息送入缓冲池;缓冲池未空,消费者可从缓冲池取走一个消息
(3)进程间需要交换信息

3.信号量设计

(1)缓冲区互斥信号量(公用):mutex
(2)生产者信号量(私有):empty 空缓冲数量
(3)消费者信号量(私有):full 满缓冲数量

4.算法设计

item B[k]; 
semaphore empty=k; //可以使用的空缓冲区,empty=0表示缓冲区满
semaphore full=0; //已经占用的缓冲区,full=0表示缓冲区为空
//缓冲区内可以使用的产品数 
semaphore mutex=1; //互斥信号量 
int in=0; 
//放入缓冲区指针 
int out=0; 
//取出缓冲区指针 
main(){ 
cobegin 
process producer_i ( ) //i=1,2,…n 
process consumer_j ( ) // j=1,2,…m 
coend 
}

//生产者
process producer_i ( ) 
{ 
while(true) { 
produce( ); 
P(empty); 
P(mutex); 
append to B[in]; 
in=(in+1)%k; 
V(mutex); 
V(full); 
} 
} 

//消费者
Process consumer_j ( ) 
{ 
while(true){ 
P(full); 
P(mutex); 
take( ) from B[out]; 
out=(out+1)%k; 
V(mutex); 
V(empty); 
consume( ); 
} 
}

5.生产者-消费者问题算法中的信号量使用分析

(1)PV操作必须成对出现(同一个程序中(互斥),不同的程序中(同步))
(2)P操作的次序很重要,使用不当会死锁
(3)V操作的次序无关紧要

类型2

1.问题描述

系统中的进程:1个生产者,1个消费者,共享1个缓冲区(缓冲区中只能放一个产品,即k=1的情形)

2.问题分析

由于缓冲区中只能放一个产品,生产者生产一个产品,消费者消费一个产品,生产者和消费者紧密同步,同步即互斥,所以缓冲池不需要互斥信号量。

3.信号量设计

(1)生产者信号量(私有):empty=1
(2)消费者信号量(私有):full=0

4.算法设计

int B; 
semaphore empty=1; 
//可以使用的空缓冲区数 
semaphore full=0; 
//缓冲区内可以使用的产品数 

main(){ 
cobegin 
process producer () 
process consumer ()  
coend 
}

process producer () { 
while(true) { 
Produce(); 
P(empty); 
append() to B; 
V(full); 
} 
} 

process consumer() { 
while(true) { 
P(full); 
take() from B; 
V(empty); 
consume(); 
} 
}

二、生产者消费者应用

例1.苹果桔子问题(两类不生产者两类消费者共享一个缓冲池)

1.问题描述

桌上有一只盘子,可容纳10个水果,每次只能放入一个水果。爸爸专向盘子中放苹果(apple),妈妈专向盘子中放桔子(orange),一个儿子专等吃盘子中的桔子,一个女儿专等吃盘子里的苹果。 请用信号量和PV操作写出能够正确执行的同步算法

2.问题分析

多类生产者多类消费者共享一个缓冲池,生产者每类一个,消费者每类一个,缓冲池大小为10
(1)互斥:盘子
(2)同步:盘子未满,爸爸或妈妈可将水果放入盘子;盘子未空,儿子或女儿可从盘子取走一个水果。
(3)进程间需要交换信息

3.信号量设计

(1)盘子互斥信号量:mutex=1
(2)生产者信号量(爸爸和妈妈两类生产者共有):disk=10
(3)儿子(消费者)信号量:orange=0
(4)女儿(消费者)信号量:apple=0

4.算法设计

semaphore disk=10,apple=0,orange=0;
 /* 盘子里可以放几个水果 , 盘子里有桔子 , 盘子里有苹果*/ 
semaphore mutex=1; //互斥的信号量 
main() { 
cobegin 
process father (); 
process mother(); 
process son (); 
process daughter (); 
coend 
}

process father() { 
While(1){ 
P(disk); 
P(mutex); 
把苹果放入plate; 
V(apple); 
V(mutex);} 
} 
process mother () { 
While(1){ 
P(disk); 
P(mutex); 
把桔子放入plate; 
V(orange); 
V(mutex); } 
} 
process son(){ 
whle(1){ 
P(orange); 
P(mutex); 
从plate中取桔子; 
V(disk); 
V(mutex);
} 
} 
process daughter() { 
while(1){ 
P(apple); 
P(mutex); 
从plate中取苹果; 
V(disk); 
V(mutex); 
}
}

例2.橘子汁问题(一个生产者,三个不同的消费者共享一个缓冲池)

1.问题描述

设有一个供应者能源源不绝地供应糖、水和橘子精,有三个负责制造橘子汁的进程,每 个进程都已经拥有了一种原材料:A 拥有糖,B 拥有水,C 拥有橘子精。供应者每次随机拿 出两种原材料供加工者加工一次。当容器中有加工者进程所需的另外两种原材料时,可以 取走相应的材料。然后供应者再像容器中放入另外两种原材料。如果没有取走原材料,则 供应者睡眠。写出供应者与加工者能正确执行的同步程序。

2.问题分析

一类生产者多类消费者共享一个缓冲池,生产者每类一个,消费者每类一个,缓冲池大小为1,紧密同步即互斥。

3.进程设计

(1)四个进程:S,A,B,C (2)S 为供应者,A,B,C 为三个负责制造橘子汁的进程,A 拥有糖,B 拥有水,C 拥有橘子精

4.信号量设计

缓冲池大小为1,紧密同步即互斥。
(1)mutex:S进程需要的信号量,初值为 1(这里信号量的命名为mutex,但是不是互斥信号量,是同步,不要混淆)
(2)SA:A 进程需要的信号量,初值为 0
(3)SB:B 进程需要的信号量,初值为 0
(4)SC:C 进程需要的信号量,初值为 0

5.算法设计

semaphore mutex=1,SA=0,SB=0,SC=0; 
cobegin 
process S() 
{ while(1) 
{ 
P(mutex); //同步即互斥 
取出两种原材料放到容器中; 
if(orange&&water) V(SA); //如果放的是 A 进程需要的材料,则唤醒 A 进程 
else if(orange&&sugar) V(SB); //如果放的是 B 进程需要的材料,则唤醒 B 进程 
else V(SC); //如果放的是 C 进程需要的材料,则唤醒 C 进程 
} 
}
process A() 
{ while(1) 
{ 
P(SA); //测试有没有 A 需要的原材料,没有则睡眠 
从容器中取走两种原材料; 
V(mutex);//唤醒生产者 S 
加工橘子汁; 
} 
}
process B() 
{ while(1) 
{ 
P(SB); //测试有没有 B 需要的原材料,没有则睡眠 
从容器中取走两种原材料; 
V(mutex);//唤醒生产者 S 
加工橘子汁; 
} 
}
process C() 
{ while(1){ 
P(SC); //测试有没有 C 需要的原材料,没有则睡眠 
从容器中取走两种原材料; 
V(mutex);//唤醒生产者 S 
加工橘子汁; 
} 
} 
coend