问题描述
系统中有一组生产者进程和一组消费者进程,生产者进程每次生产一个产品放入缓冲区,消费者进程每次从缓冲区取出一个产品并使用。(这里的"产品"理解为某种数据)
生产者、消费者共享一个初始为空、大小为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); //增加一个空闲缓冲区
使用产品
}
}
能否改变相邻P、V操作的顺序?
producer() {
while(1) {
生产一个产品;
P(mutex); 1
P(empty); 2
把产品放入缓冲区;
V(mutex);
V(full);
}
}
consumer() {
while(1) {
P(mutex); 3
P(full); 4
从缓冲区取出一个产品
V(mutex);
V(empty);
使用产品
}
}
若此时缓冲区已经放慢了产品,则empty = 0,full = n。
则生产者进程执行 1 使mutex变为0,再执行 2 ,由于已经没有空闲缓冲区,因此生产者被阻塞。由于生产者阻塞,因此切换回消费者进程。消费者进程执行 3 ,由于mutex为0,即生产者还没释放对临界资源的"锁",因此消费者也被阻塞。
这就造成了生产者等待消费者释放空闲缓冲区,而消费者又等待生产者释放临界区的情况,生产者和消费者循环等待被对方唤醒,出现"死锁"。
同样的,若缓冲区中没有产品,即full = 0,empty = n。按 3、4、1的顺序执行就会发生死锁。
因此,实现互斥的P操作一定要在实现同步的P操作之后。
V操作不会导致进程阻塞,因此两个V操作顺序可以交换。