生产者消费者问题
问题描述
有一群生产者进程生产产品,并将这些产品提供给消费者进程去消费。为使生产者进程与消费者进程能并发执行,在两者之间设置一个具有n个缓冲池的缓冲区,生产者进程将其所生产的产品放入一个缓冲区中;消费者进程可以从一个缓冲区中取走产品进行消费。尽管所有生产者进程和消费者进程都是异步运行的,但他们之间必须保持同步,既不允许消费者进程到一个空的缓冲区去取产品,也不允许生产者进程向一个已装满产品且尚未被取走的缓冲区投放产品。
一.利用记录型信号量解决
- 生产者和消费者之间的公用缓冲池有n个缓冲区
- 用互斥信号量mutex实现多进程对缓冲池的互斥使用
- 利用信号量empty和full分别表示缓冲池中空缓冲区的数量和满缓冲区的数量
int in=0,out=0;
item buffer[n];
semaphore mutex=1,empty=n,full=0;
//----------生产者---------------
void producer () {
do{
producer an item nextp;
...
wait(empty);
wait(mutex);
buffer[in]=nextp;
in=(in+1)%n;
signal(mutex);
signal(full);
}while(TRUE);
}
//------------消费者---------------
void consumer () {
do{
wait(full);
wait(mutex);
nextc=buffer[out];
out=(out+1)%n;
signal(mutex);
signal(empty);
consumer the item in nextc;
...
}while(TRUE);
}
//---------主程序并发执行进程----------
void main()
{
cobegin
producer(); consumer();
coend
}
每个程序中的多个wait操作顺序不能颠倒,应先执行对资源信号量的wait操作,然后再执行对互斥信号量的wait操作,否则可能引起死锁。
二.利用AND信号量解决
- 用Swait(empty,mutex)代替wait(empty)和signal(mutex)
- 用Swait(full,mutex)代替wait(full)和signal(mutex)
- 用Ssignal(empty,mutex)代替signal(empty)和signal(mutex)
- 用Ssignal(full,mutex)代替signal(full)和signal(mutex)
int in=0,out=0;
item buffer[n];
semaphore mutex=1,empty=n,full=0;
//------------生产者---------------
void producer(){
do{
producer an item nextp;
...
Swait(empty,mutex);
buffer[in]=nextp;
in=(in+1)%n;
Ssignal(full,mutex);
}while(TRUE);
}
//------------消费者-----------------
void consumer(){
do{
Swait(full,mutex);
nextc=buffer[out];
out=(out+1)%n;
Ssignal(empty,mutex);
consume the item in nextc;
...
}while(TRUE);
}
三.利用管程解决
-
首先建立一个管程,名命为producerconsumer,简称PC。
-
管程包含两个过程
- put(x)过程:生产者利用该过程将自己生产的产品投放到缓冲池中,并用整型变量count来表示在缓冲池中已有的产品数目,当count>=N时,表示缓冲池已满,生产者须等待。
- get(x)过程:消费者利用该过程从缓冲池中取出一个产品,当count<=0时,表示缓冲池中已无可取用的产品,消费者应等待。
-
对于条件变量notfull和notempty,分别有两个过程对他们进行操作:
- cwait过程:当管程被一个进程占用时,其他进程调用该过程时阻塞,挂在条件condition队列上。
- csignal过程 :唤醒在cwait执行后阻塞在condition队列上的进程,如果这样的进程不止一个,则选择其中一个唤醒;如果队列为空,则无操作而返回。
PC管程定义如下:
Monitor producerconsumer{
item buffer[N];
int in,out;
condition notfull,notempty;
int count;
public:
//---------put过程-----------
void put(item x){
if(count>=N) cwait(notfull);
buffer[in]=x;
in=(in+1)%N;
count++;
csignal(notempty);
}
//--------get过程------------
void get(item x){
if(count<=N) cwait(notempty);
x=buffer[out];
out=(out+1)%N;
count--;
csignal(notfull);
}
{in=0; out=0; count=0;}
}PC;
用上述管程定义实现生产者消费者:
//----------生产者-----------
void producer(){
item x;
while(TRUE){
...
produce an item in nextp;
PC.put(x)
}
}
//----------消费者------------
void consumer(){
item x;
while(TRUE){
PC.get(x);
consume the item in nextc;
...
}
}
void main(){
cobegin
producer(); consumer();
coend
}