视频链接:
https://www.bilibili.com/video/BV1YE411D7nH?p=24
一,问题描述:
桌上有一只盘子,每次只能向其中放入一个水果。
爸爸向盘子中只放苹果,妈妈向盘子中只放橘子,儿子只吃橘子,女儿只吃苹果。
只有盘子为空时,爸爸妈妈才可以向盘子中放入 一个水果。
仅当盘子中有自己需要的水果时,儿子或者女儿才可以从盘子中取出水果。用PV操作实现以上过程
二,问题分析
1,关系分析:找出题目中描述各个进程,分析他们之间的同步关系
1)互斥关系:对缓冲区(盘子)的访问需要互斥的进行
2)同步关系(一前一后)
父亲将苹果放入盘中,女儿才能取苹果
母亲将橘子放入盘中,儿子才能取橘子
只有盘子为空时,父亲母亲才能放水果——盘子为空的事件可以是儿子触发,也可以是女儿
2,整理思路:根据各个进程的操作流程确定P,V操作的大致顺序
互斥:需要在临界区前后分别执行P操作,和V操作。
同步:前一个进程执行后执行V操作,后一个进程进入临界区之前执行P操作
3,设置信号量:设置需要的信号量,并根据题目条件确定信号量的初值。
互斥信号量一般初值为1
同步信号量的初值要看对应资源的初始值
三,具体实现:
刚开始,儿子,女儿即使上处理机运行也会被堵塞。如果刚开始是父亲进程上处理机运行,则:父亲P(plate),可以访问盘子——》如果这是突然切换到母亲进程,到P(plate),就会被堵塞——》返回父亲进程继续执行,父亲放入苹果V(apple)——》唤醒女儿进程,如果此时运行的是其他进程则会被堵塞,暂时不能访问盘子,等待女儿进程执行完毕V(plate),触发盘子为空——》唤醒在等待队列中的母亲进程P(orange)——》唤醒儿子进程执行。
semaphore mutex=1; //互斥实现访问盘子
semaphore apple=1; //盘子中有几个苹果
semaphore orange=1; //互盘子中有几个橘子
semaphore plate=1; //盘子中还可以放入几个水果
//父亲进程
dad(){
while(1){
准备一个苹果;
p(plate);//对盘子进行P操作(plate--),plate=0,表示盘子中有水果
P(mutex);//互斥访问盘子
把苹果放入盘子;
V(mutex);
v(apple);//对盘子进行V操作(apple++),apple=1,唤醒需要苹果的进程
}
}
//目前进程
mom(){
while(1){
准备一个橘子;
P(plate);
P(mutex);
把橘子放入盘子;
v(mutex);
v(orange);
}
}
//女儿进程
daughter(){
while(1){
P(apple);//如果apple=1,即盘子中有苹果,满足要求继续执行
P(mutex);//对盘子进行互斥访问
把苹果从盘子取出;
v(mutex);
v(apple);
吃的苹果;
}
}
//儿子进程
son(){
while(1){
P(orange);
P(mutex);
从盘中取出橘子;
V(mutex);
V(plate);
吃掉橘子;
}
}
三,重要考点:
解决"多生产者-多消费者”问题的关键在于理清复杂的同步关系。
在分析同步问题(一前一后问题)的时候不能从单个进程行为的角度来分析,要把一前一后发生的事看做两种事件的前后关系。
比如,如果从单个进程行为的角度考虑的话,我们会有以下结论:
如果盘子里有苹果,那么一定要女儿进程取出苹果后,父亲或母亲进程才能放入水果
如果盘子里有橘子,那么一定要儿子进程取出橘子后,父亲或母亲进程才能放入水果
这么看是否就意味着要设置四个同步信号量分别来实现这四个一前一后的关系?
正确的分析方法是:
从事件的角度考虑,我们可以把上述四对一前一后的进程关系,抽象成一对事件的前后关系:盘子为空事件——》放入水果事件。盘子为空事件可以由儿子引发也可以是女儿引发;放入水果事件既可以是父亲执行,也可以是母亲执行。这样的话用一对信号量就可以解决问题了