多生产者-多消费者问题

  • Post author:
  • Post category:其他




1 问题描述

桌子上有一只盘子,每次只能向其中放入一个水果。爸爸专向盘子中放苹果,妈妈专向盘子中放橘子,儿子专等着吃盘子中的橘子,女儿专等着吃盘子中的苹果。只有盘子空时,爸爸或妈妈才可向盘子中放一个水果。仅当盘子中有自己需要的水果时,儿子或女儿可以从盘子中取出水果。

在这里插入图片描述



2 问题分析

  1. 关系分析。找出题目中描述的各个进程,分析它们之间的同步、互斥关系。

    多生产者-多消费者问题关系分析如下:

互斥关系: 对缓冲区(盘子)的访问要互斥地进行

同步关系(一前一后):

  1. 父亲将苹果放入盘子后,女儿才能取苹果
  2. 母亲将橘子放入盘子后,儿子才能取橘子
  3. 只有盘子为空时,父亲或母亲才能放入水果

注意:“盘子为空”这个事件可以由儿子或女儿触发,事件发生后才允许父亲或母亲放水果

  1. 整理思路。根据各进程的操作流程确定P、V操作的大致顺序。

由以上的同步、互斥关系分析,将多生产者-多消费者问题描绘出图形:

在这里插入图片描述

  1. 设置信号量。设置需要的信号量,并根据题目条件确定信号量初值。

    (互斥信号量初值一般为 1,同步信号量的初始值要看对应资源的初始值是多少)


    本问题中信号量设置如下:
  semaphore mutex = 1;    //实现互斥访问盘子(缓冲区)
  semaphore apple = 0;    //盘子中有几个苹果 
  semaphore orange = 0;   //盘子中有几个橘子
  semaphore plate = 1;    //盘子中还可以放多少个水果
  1. 模型实现:

    在这里插入图片描述


    dad

    :先准备一个苹果,放苹果之前,先判断盘子里是否为空(P一下盘子,检查盘子中还可以放多少个水果),然后再将苹果放入进去(V一下苹果,数量+1)


    mom

    :先准备一个橘子,放橘子之前,先判断盘子里是否为空(P一下盘子,检查盘子中还可以放多少个水果),然后再将橘子放入进去(V一下橘子,数量+1)


    daughter

    :拿苹果之前,先判断盘子里有没有苹果(P一下苹果,若没有苹果,自己被阻塞),然后告诉父母,盘子为空了(V一下盘子)


    son

    :拿橘子之前,先判断盘子里有没有橘子(P一下橘子,若没有橘子,自己被阻塞),然后告诉父母,盘子为空了(V一下盘子)


以下实现了所有进程之间的同步关系:

在这里插入图片描述

还需要实现各个进程对盘子(缓冲区)的互斥访问:

就是所有进程对盘子进行PV操作,即加锁和解锁的过程

在这里插入图片描述



3 代码实现

 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);           //允许父母进程进程向盘子中取放水果
           吃橘子;
    }
}



4 分析总结

  1. 问题:可不可以不用互斥信号量?

    结论:即使不设置专门的互斥变量

    mutex

    ,也不会出现多个进程同时访问盘子的现象

    原因在于:本题中的缓冲区大小为1,在任何时刻,

    apple、orange、plate

    三个同步信号量中最多只有一个是1。因此在任何时刻, 最多只有一个进程的P操作不会被阻塞,并顺利地进入临界区…
  1. 若将缓冲区设置为2会发生什么现象?

    父亲P(plate),可以访问盘子→母亲P(plate),可以访问盘子→父亲在往盘子里放苹果,同时母亲也可以往盘子里放橘子。于是就出现了两个进程同时访问缓冲区的情况,有可能导致两个进程写入缓冲区的数据相互覆盖的情况。

因此,如果缓冲区大小大于1,就必须专门设置一个互斥信号量

mutex

来保证互斥访问缓冲区。

  1. 总结:在生产者-消费者问题中,如果缓冲区大小为1,那么有可能不需要设置互斥信号量就可以实现 互斥访问缓冲区的功能。当然,这不是绝对的,要具体问题具体分析。
  1. 建议:在考试中如果来不及仔细分析,可以加上互斥信号量,保证各进程一定会互斥地访问缓冲区。 但需要注意的是,实现互斥的P操作一定要在实现同步的P操作之后,否则可能引起“死锁”。


理解理清复杂的同步关系:


在分析同步问题(一前一后问题)的时候

不能从单个进程行为的角度来分析,要把“一前一后”发生的事看做是两种“事件”的前后关系。

比如,如果从单个进程行为的角度来考虑的话,我们会有以下结论:

  1. 如果盘子里装有苹果,那么一定要女儿取走苹果后父亲或母亲才能再放入水果
  2. 如果盘子里装有橘子,那么一定要儿子取走橘子后父亲或母亲才能再放入水果
  3. 这么看是否就意味着要设置四个同步信号量分别实现这四个“一前一后”的关系了?

    在这里插入图片描述

正确的分析方法应该

从“事件”的角度来考虑

我们可以把上述四对“进程行为的前后关系”抽象为 一对“事件的前后关系”

  1. 盘子变空事件→放入水果事件。“盘子变空事件”既可由儿子引发,也可由女儿引发;
  2. “放水果事件” 既可能是父亲执行,也可能是母亲执行。
  3. 这样的话,就可以用一个同步信号量解决问题了

    在这里插入图片描述



版权声明:本文为C2925811081原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。