目录
1.问题描述
要求如下:
- 只要缓冲区没满,生产者才能把产品放入缓冲区,否则必须等待。
- 只有缓冲区不空时,消费者才能从中取出产品,否则必须等待。
- 缓冲区是临界资源,各进程必须互斥地访问。
2.问题分析
如何用信号量机制(P、V操作)实现生产者、消费者进程的这些功能呢?信号量机制可以实现互斥、同步、对一类资源的申请和释放。
- 互斥:设置初值为1的互斥信号量。
- 同步:设置初值为0的同步信号量(实现“一前一后”)。
- 对同一类资源的申请和释放:设置一个信号量,初值为资源的数量(本质上也属于“同步问题”,若无空闲资源,则申请资源的进程需要等待别的进程释放资源后才能继续往下执行)。
生产者-消费者问题中的同步关系:
- 同步关系:缓冲区满时,生产者要等待消费者取走商品。
- 同步关系:缓冲区为空时(即没有产品时),消费者要等待生产者放入商品。
生产者-消费者问题中的互斥关系:
- 互斥关系:缓冲区是临界资源,各进程之间必须互斥。
3.问题实现
3.1 初始化
semaphore mutex = 1;//互斥信号量,实现对缓冲区的互斥访问
semaphore empty = n;//同步信号量,实现空闲缓冲区的数量
semaphore full = 0;//同步信号量,标识产品数量,也即非空缓冲区的数量
3.2 生产者
producer(){
while(1){
生产一个产品;
P(empty);//消耗一个空闲缓冲区
P(mutex);
把产品放入一个缓冲区;
V(mutex);
V(full);//增加一个产品
}
}
3.3 消费者
consumer(){
while(1){
P(full);//消耗一个产品(非空缓冲区)
P(mutex);
从缓冲区取出一个产品;
V(mutex);
V(empty);//增加一个空闲缓冲区
使用产品;
}
}
思考:如果改变相邻P操作的顺序会出现什么情况?
若此时缓冲区内已经放满产品,则empty=0,full=n。
生产者执行P(mutex)使得mutex=0,再执行P(empty),由于已经没有空闲缓冲区。因此生产者被阻塞。由于生产者被阻塞,因此切换回消费者进程。消费者进程执行P(mutex),由于mutex=0,即生产者还没有释放对临界资源的“锁”,因此消费者也被阻塞。
这就造成了生产者等待消费者释放空闲的缓冲区,而消费者又等待生产者释放临界区的情况,生产者和消费者循环等待被对方唤醒,出现“死锁”。因此,实现互斥地P操作一定要在实现同步的P操作之后。