一.问题描述
- 有一个盘子,每次只能放一个水果
- 父亲专门往盘子里放苹果,母亲专门往盘子里放橘子
- 女儿专门等着吃盘子里的苹果,儿子专门等着吃盘子里的橘子
- 只有盘子为空时,父亲/母亲才可向盘子里放入一个水果
- 只有盘子里有自己需要的水果时,女儿/儿子才会从盘子里拿水果
- 这就是多生产者多消费者问题,所谓的“多”其实是多类型:即不同类型的生产者和不同类型的消费者
二.问题分析
在这个题目中,父亲和母亲其实就是两个生产者进程,儿子和女儿就是两个消费者进程,盘子其实就是一个大小为1的缓冲区
1.关系分析
找出题目中描述的各个进程,分析他们之间的互斥和同步关系
- 互斥关系:对缓冲区(盘子)的访问要互斥的进行
- 同步关系1:父亲将苹果放入盘子之后,女儿才能取苹果
- 同步关系2:母亲将橘子放入盘子之后,儿子才能取橘子
- 同步关系3:只有盘子为空时,父亲/母亲才能放入水果
- “盘子为空”这个事件可以由儿子/女儿触发,事件发生后才允许父亲/母亲放水果
2.整理思路
根据各进程的操作流程确定P、V操作的大致执行顺序
- 互斥:在访问临界区前后加P、V操作
- 同步:在上面分析的各个同步关系中:前操作之后加V操作,后操作之前加P操作
3.设置信号量
- 设置需要的信号量,并根据题目设置初值
- 互斥信号量初值一般为1
- 同步信号量初值根据对应资源的初始值确定
- mutex=1:实现互斥访问缓冲区
- apple=0:盘子中有几个苹果
- orange=0:盘子中有几个橘子
- plate=1:盘子中此时还能放几个水果
4.具体实现
- 父亲进程:先准备一个苹果,在放入盘子之前,先检查盘子中是否有水果(对信号量mutex执行P操作),如果此时盘子中没有水果,那么父亲就将苹果放入盘子,并且对信号量apple执行V操作,表示此时盘子中有一个苹果。母亲进程的执行与之类似。
- 女儿进程:先检查盘子中是否有苹果(对信号量apple执行P操作),如果有则从盘子中取出苹果,并且执行V(plate),表示此时盘子空了,可以继续放水果了。儿子进程的执行与之类似。
5.补充
在对同步关系(只有盘子为空时,父亲/母亲才能放入水果)的处理中,如果从单个进程行为的前后关系来考虑,会有以下结论:
- 如果盘子内装有苹果,那么一定要女儿取走苹果,父亲/母亲才能再放入水果
- 如果盘子内装有橘子,那么一定要儿子取走橘子,父亲/母亲才能再放入水果
- 那么就会产生四对一前一后的关系,需要四个信号量来实现:
但如果我们是从某个事件发生前后的角度考虑,盘子变空事件—>放入水果事件,盘子变空可以由儿子/女儿触发,放入水果可以由父亲/母亲执行,这样只用一个信号量就可以解决问题