生产者消费者问题是一个经典的同步问题,问题的描述如下:
一组生产者进程和一组消费者进程共享一个初始为空,大小为n的缓冲区,只有缓冲区没满时,生产者才能把消息放入缓冲区,否则必须等待,只有缓冲区不空时,消费者才能从中取出消息,否则只能等待。由于缓冲区时临界资源,只允许一个生产者放入消息,或者一个消费者取出消息。
问题分析:
- 生产者与消费者对缓冲区的访问是互斥关系,同时又是一个相互协作关系,即只有生产者产生消息,消费者才能取出消息,因此又是一个同步问题。
- 信号量设置,设置一个信号量mutex为互斥信号量,初始值为1,信号量full记录缓冲池中已满的缓冲区数目,初始为0,信号量empty记录缓冲池中空的缓冲区数目,初始为n。
实现如下
semaphore mutex=1;
semaphore empty=n;
semaphore full=0;
producer(){
while(1){
//生产一个消息
P(empty);//获取空缓冲区单元
P(mutex);//进入临界区
//将消息添加到缓冲区
V(mutex);
V(full);
}
}
consumer(){
while(1){
P(full);
P(mutex);
//取出一个消息
V(mutex);
V(empty)
}
}
分析:
首先对于互斥问题,需要设置一个互斥信号量,同时为保证只有一个进程能够进入临界区,信号量需设置为1。对于同步问题,因为缓冲池大小为n,缓冲区空时生产者可以放入消息,缓冲区满时,消费者可以取出消息,因此设置两个信号量,分别对应满的缓冲区和空缓冲区数目,两个信号量相加应为n。
同时,对empty和full的P操作,需放在mutex之前。这是因为生产者线程只对empty有需求,当生产者线程对empty执行P操作后,empty为0,对消费者线程并没有影响。而若是对mutex的P操作放在前,假设生产者已经将缓冲区放满,此时empty为0,消费者也没有取出消息。而此时又运行生产者线程时,生产者先封锁mutex信号量,然后执行P(empty)操作,阻塞后,其等待消费者线程取出消息并唤醒自身。此时执行消费者线程时,由于mutex已经被生产者锁定,消费者也会阻塞,希望生产者唤醒自己。那么双方都会阻塞。
网友评论