一、生产者--消费者问题
类型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