文章目录

  • 1 问题描述
  • 2 问题分析
  • 3 代码实现
  • 4 分析总结

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. 这样的话,就可以用一个同步信号量解决问题了

多生产者-多消费者问题相关推荐

  1. RabbitMQ 入门系列(2)— 生产者、消费者、信道、代理、队列、交换器、路由键、绑定、交换器

    本系列是「RabbitMQ实战:高效部署分布式消息队列」和 「RabbitMQ实战指南」书籍的读书笔记. RabbitMQ 中重要概念 1. 生产者 生产者(producer)创建消息,然后发送到代理 ...

  2. linux进程间通信:system V 信号量 生产者和消费者模型编程案例

    生产者和消费者模型: 有若干个缓冲区,生产者不断向里填数据,消费者不断从中取数据 两者不冲突的前提: 缓冲区有若干个,且是固定大小,生产者和消费者各有若干个 生产者向缓冲区中填数据前需要判断缓冲区是否 ...

  3. Python中的生产者与消费者模式(转载)

    利用多线程和队列可以实现生产者消费者模式.该模式通过平衡生产线程和消费线程的工作能力来提高程序整体处理数据的速度. 1.什么是生产者和消费者? 在线程世界里,生产者就是生产数据(或者说发布任务)的线程 ...

  4. 12.多线程的实现方式、线程安全问题的产生与解决以及生产者与消费者问题

    一.实现多线程 1.1 了解多线程 多线程是指从软件或者硬件上实现多个线程并发执行的技术,具有多线程能力的计算机因有硬件支持而能够在同一时间执行多个线程,从而提升性能. 1.2 并发与并行 并行是指同 ...

  5. java多线程 生产者消费者_java多线程之-生产者与消费者

    java多线程之-并发协作[生产者与消费者]模型 对于多线程程序来说,不管c/c++ java python 等任何编程语言,生产者与消费者模型都是最为经典的.也就是可以说多线程的并发协作 对于此模型 ...

  6. python生产和消费模型_python queue和生产者和消费者模型

    queue队列 当必须安全地在多个线程之间交换信息时,队列在线程编程中特别有用. classqueue.Queue(maxsize=0) #先入先出classqueue.LifoQueue(maxsi ...

  7. 基于java多线程来实现生产者和消费者的实例

    声明:本实例是在网上看到,做了很小的修改.所以感谢之前的作者.只是一时忘了哪儿看到,没法加入链接,向原作者道歉,以示尊重.抱歉-^)... 同步栈: 1 class SycnStack { 2 pri ...

  8. PV操作——生产者和消费者

    首先,先来看几个概念: 同步:协作的过程,比如,多人开发合作. 相互排斥:争抢资源的过程.比如苦逼的大学选课: 临界区:进程中对临界资源实施操作的那段程序: 临界资源:一次仅仅能一个进程使用的资源,比 ...

  9. 线程通信问题--生产者和消费者问题

    一.问题引入:首先实现一个线程通信的实例,使用两个线程交替打印输出100以内的数字. 代码实现如下: 1 package com.baozi.exer; 2 3 public class Commun ...

  10. Java中生产者与消费者问题的演变

    想要了解更多关于Java生产者消费者问题的演变吗?那就看看这篇文章吧,我们分别用旧方法和新方法来处理这个问题. 生产者消费者问题是一个典型的多进程同步问题. 对于大多数人来说,这个问题可能是我们在学校 ...

最新文章

  1. opencv meanStdDev
  2. 线段覆盖加强版(快速+贪心)
  3. Eclipse 运行程序
  4. WPF 分页控件添加路由事件
  5. 如何释放mysql连接资源_CI框架出现mysql数据库连接资源无法释放的解决方法
  6. python 爬虫工具 butter_GitHub - TheButterflyOdor/proxy_pool: Python爬虫代理IP池(proxy pool)
  7. php文件上传漏洞防御,第十二课 php文件上传漏洞和代码防御
  8. 为何要搞 10 年?方舟编译器专家首次回应
  9. 蓝桥杯 ADV-211 算法提高 2-2整数求和
  10. 1121: [POI2008]激光发射器SZK
  11. 阶段1 语言基础+高级_1-3-Java语言高级_09-基础加强_第2节 反射_5_反射_概述
  12. JVM内存模型和JAVA内存模型的区别
  13. socket服务器和客户端的建立步骤
  14. 人工智能该如何学习?详细的AI学习路线与资料推荐
  15. Leetcode-数据结构-217. 存在重复元素
  16. 什么是浏览器指纹? 浏览器指纹技术应用有哪些?
  17. (附源码)计算机毕业设计SSM基于的仓库管理系统
  18. 什么是上下文切换?如何减少上下文切换?
  19. js高级jQuery框架easyUI框架
  20. hacs增加源_GDP-32多功能电法工作站,可控源音频大地电磁

热门文章

  1. 每日一练(8)—— 野指针
  2. 利用qsort二级排序
  3. 下载Pytorch的自带数据集时报错=urllib.error.URLError: urlopen error [SSL: CERTIFICATE_VERIFY_FAILED]
  4. wget python3_python wget
  5. python的普通方法、类方法和静态方法
  6. LeetCode 638. 大礼包(无限背包DP)
  7. 程序员面试金典 - 面试题 04.12. 求和路径(二叉树递归)
  8. LeetCode 653. 两数之和 IV - 输入 BST(二叉搜索树迭代器双指针)
  9. 武林c语言,详解C语言中条件编译
  10. vue弹出alert_vue+webpack 实现简单的弹窗(alert)组件