多消费者-多生产者问题

先给出问题背景:桌子上有一个盘子,每次只能向其中放入一个水果,爸爸专向盘子里放苹果,妈妈专向盘子里放橘子,儿子专等着吃盘子里的橘子,女儿专等着吃盘子里的苹果。只有字盘子是空的时候,爸爸或妈妈才能向盘子里放水果;只有在盘子里有自己想要的水果时,儿子或女儿才能取出盘子里的水果吃掉。

分析:

对盘子的访问要互斥

同步关系(一前一后)

1 父亲将苹果放进盘子后,女儿才能取走苹果

2 母亲将橘子放进盘子后,儿子才能取走橘子

3 盘子为空时,爸爸或妈妈才能往盘子里放水果(盘子为空这个事件可以由女儿或儿子触发)

图示

根据上面的分析,我们可以得出下面的几个信号量

1
2
3
4
semaphore mutex = 1; //互斥信号量
semaphore apple = 0;
semaphore orange = 0;
semaphore plate = 1;//一开始父亲或母亲就可以放水果,可以理解为空闲大小

具体代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
semaphore mutex = 1;
semaphore apple = 0;
semaphore orange = 0;
semaphore plate = 1;
dad(){
while(1){
准备一个苹果;
P(plate);
P(mutex);
把苹果放入盘子;
V(mutex);
V(apple);
}
}
mom(){
while(1){
准备一个橘子;
P(plate);
P(mutex);
把苹果放入盘子;
V(mutex);
V(orange);
}
}
daughter(){
while(1){
P(apple);
P(mutex);
取出盘子里的水果;
V(mutex);
V(plate);
吃苹果;
}
}
son(){
while(1){
P(orange);
P(mutex);
取出盘子里的水果;
V(mutex);
V(plate);
吃苹果;
}
}

注意这里还是互斥的P操作要写在同步的P操作之后,避免产生死锁问题

现在来考虑考虑,我可不可以不要互斥信号量?

一开始盘子为空,女儿和儿子想运行都会被阻塞,如果父亲先操作,那么会让plate变成0,这个时候母亲要是想放橙子会被阻塞;女儿当然可以拿苹果,其他进程都会被阻塞,如此分析看来,我不要互斥信号量是完全ok的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
semaphore apple = 0;
semaphore orange = 0;
semaphore plate = 1;
dad(){
while(1){
准备一个苹果;
P(plate);
把苹果放入盘子;
V(apple);
}
}
mom(){
while(1){
准备一个橘子;
P(plate);
把苹果放入盘子;
V(orange);
}
}
daughter(){
while(1){
P(apple);
取出盘子里的水果;
V(plate);
吃苹果;
}
}
son(){
while(1){
P(orange);
取出盘子里的水果
V(plate);
吃苹果;
}
}

那如果我的盘子可以放两个水果呢?plate的初始值就是2,当父亲放进苹果后,plate变为1,母亲也想放橙子,发现也可以,于是就出现了父亲母亲同时访问缓冲区的情况,因而,如果缓冲区容量为1,我们可以不设互斥信号量,但如果缓冲区容量大于1,就必须设置信号量

那为了避免出麻烦,我们就不管三七二十一都给他设上互斥信号量,肯定是没有问题的。

最后想说一个思想,在多消费者多生产者的问题中,不同于之前的生产者消费者问题,我们不应该把每个进程看成一个整体来考虑问题,应该将事件拿出来分析问题

就上面的问题来讲,如果我不按时间角度来分析,那就是只有儿子将橘子取走了,母亲才能向盘子里放橘子;只有女儿将苹果取走了,爸爸才能把苹果放在盘子里;那仔细想想,我一定要有这个先后顺序吗,比如说女儿取走苹果之后,既可以是母亲方橘子,也可以是父亲放苹果,因此应该想象成事件间的前后关系,就是只有盘子空了,父亲或母亲才能放水果。

再者,通过栗子,我们应该明白,所谓多消费者多生产者应该不是数量上的多,而应该是种类上的多。

-------------本文结束感谢您的阅读-------------