问题描述
一组生产者进程和一组消费者进程共享一个初始为空、大小为n的缓冲区,只有缓冲区没满时,生产者才把消息放入缓冲区,否则必须等待;只有缓冲区没空时,消费者从中取出消息,否则必须等待。由于缓冲区是临界资源,它只允许一个生产者放入消息,或一个消费者从中取出消息。
对于同步互斥的解释
首先,在操作系统中的异步指的是进程以不可预知的速度前进,举个例子来说,我想打LOL,需要我先打开客户端登陆,才能打LOL,因此打LOL这个动作要发生在客户端登陆之后,这就是所谓同步(用于进程间的相互制约)。
问题分析
- 关系分析
首先,临界区的意思是一次只能由一个进程访问。而如果一次有两个消费者进程要去访问临界区,那么可能会出现一个进程获得了一些资源,另一个进程获得了另一半资源,造成资源的分配不全,生产者进程也是会造成这样的问题。因此生产者和消费者对于临界区的访问是互斥关系
其次,消费者只有在生产者生产之后才能消费,而生产者也需要在消费者消费后(使资源不满)才能再生产。这种先后的顺序则是同步关系 - 信号量设置
在此问题中,互斥关系有一对,而同步关系有两对。
mutex为互斥信号量,初值为1,用于控制互斥访问。
full为同步信号量,初值为0,记录当前缓冲区中满的缓冲区数
empty为同步信号量,初值为n,记录当前缓冲区中空的缓冲区数
semaphore mutex=1;
semaphore empty=N;//N表示当前总共有几个缓冲区,empty=N即当前缓冲区均为空
semaphore full=0;Consumer(){while(1){P(full);//需要有满的存有数据的缓冲区P(mutex);visit()//访问临界区,并消费V(mutex);V(empty);//提供一个空的缓冲区可供生产}
}Producer(){while(1){P(empty);//需要空的缓冲区来生产P(mutex);visit()//访问临界区,并生产V(mutex);V(full);//提供一个满的缓冲区可供消费}
}
注意
对于mutex的PV操作一定要和临界区代码"夹紧",考虑这样一种情况:
当缓冲区已满,empty=0,full=n时
当前面生产者代码中P(empty);P(mutex);
互换顺序,先对mutex进行P操作,再对full执行P操作,转换成人话就是在说:我先进入了临界区,但我就是不出去,与此同时我又申请了空闲的缓冲区,因为缓冲区均满,所以P(empty)
会锁住,等待消费者代码那的V(empty)
来唤醒自己,但是问题就出在这里。
消费者那里的V(empty)在代码的末尾,执行消费者进程时,我还需执行P(mutex)
但人生产者还在临界区没出来,你怎么能进的去?所以这里也锁住,等待生产者那边的V(mutex)来唤醒自己。
相信大家也看出来了,这不是我等你你等我谁也等不到嘛?所以这样的交换是有问题的,不能够交换这两句代码的顺序。