# 生产者与消费者算法模拟
## 问题描述
(1) 设计题目:生产者与消费者算法模拟
(2) 基本内容:
① 创建三个进程,一个是生产者进程,两个是消费者进程。
② 父子进程都使用父进程创建的共享存储区进行通信,由生产者进程将一个数组中的十个数发送到由 5 个缓冲区组成的共享内存中。
③ 两个消费者进程轮流接收并输出这十个数值,同时将两个消费者进程读出的数值进行累加求各和。
(3) 实验目的:掌握信号的使用方法和 P、V 操作,实现进程之间同步与互斥,加深对进程同步互斥概念的理解。
## 需求分析
生产者--消费者问题是一个经典的进程同步问题。既然有进程间的同步,也就必将涉及到进程之间的互斥与通信问题,对于这个问题的解决有着很强的现实意义。它的现实意义在于可以类比到计算机中对于临界资源的互斥共享。生产者与消费者就好比是对计算机临界资源访问的程序或用户,而临界资源如打印机、磁带等设备。
具体的问题模型分为两种,具体比较如下表 2-1 所示。
表 2-1 模型对比表
| 模型 | 单个生产者 + 单个消费者 | 若干个生产者 + 若干个消费者 |
| -------- | ------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------- |
| 内容要求 | 当缓冲区为空时,消费者不能从其中取出数据。当缓冲区为满时,生产者不能向其中写入数据。 | 同时只能有一个生产者向缓冲区写入数据。当缓冲区为空时,消费者不能从其中取出数据。当缓冲区为满时,生产者不能向其中写入数据。 |
对于第二种模型,此时的示意图如图 2-1 所示。
![](https://www.writebug.com/myres/static/uploads/2022/1/15/4cf8e5e8b77fe0c4de7212cf0fbef85a.writebug)
图 2-1 多生产者消费者模型示意图
## 概要设计
### 思路方法
本次思路从信号量优化而来。
Step1: 在主函数中设计一个 data 数组,并对其随机赋值,然后随机创建若干各生产者进程与消费者进程,随机选取一个就绪状态的进程并执行。
Step2: 使用独有的 LinkedBlockingQueue 数据结构来实现,BlockingQueue 阻塞队列方法已经在内部实现了同步,底层仍然采用的是 await 和 signal 的方法,但是它可在生成对象时指定容量大小,用于阻塞操作的是 put()和 take()方法,可以在加锁的前提下自动完成阻塞的一系列动作,无需再进行其他的手动操作。最后记录中断位置,再随机选取一个就绪进程重复以上步骤。
Step3: 使用了第三方的 Jxl 的 Jar 包将所有的数据导入到 Excel 表中,并通过 Python 呈现到图中。
### 程序流程图
总体流程图如图 3-1 所示,生产者的流程图如图 3-2 所示,消费者的流程图如 3-3 所示。
![](https://www.writebug.com/myres/static/uploads/2022/1/15/e13c918e60705f9942bc1e7d100802df.writebug)
图 3-1 总体流程图
![](https://www.writebug.com/myres/static/uploads/2022/1/15/75a4ff54d20620f58ee2fd5c3c3076ee.writebug)
图 3-2 生产者流程图
![](https://www.writebug.com/myres/static/uploads/2022/1/15/2342528d5efa6dcb9c7baf6c2bf8d8eb.writebug)
图 3-3 生产者流程图
## 详细设计
### 数据结构
本次课程设计中采用 Java 中独有的 LinkedBlockingQueue 数据结构来实现,BlockingQueue 阻塞队列方法在内部实现同步,底层仍采用 await 和 signal 的方法,但它可在生成对象时指定容量大小,使用 put()和 take()方法可以自动阻塞,可以在加锁的前提下自动完成阻塞的一系列动作,无需再进行其他的手动操作,具体的示意图如图 4-1 所示。
![](https://www.writebug.com/myres/static/uploads/2022/1/15/51ca83d61f7e5c5d90b184e9736ff646.writebug)
图 4-1 阻塞队列示意图
### 生产者/消费者模式与进程通信
生产与消费模式需使用到同步及线程,属于多并发问题,在本设计中将生产整型数字的模块称为生产者,而获取整形数据的模块,就称为消费者。该模式还需要有一个缓冲区处于生产者和消费者之间,作为一个中介。生产者把数据放入缓冲区,而消费者从缓冲区取出数据。
针对解耦问题,由于生产者和消费者都依赖于缓冲区,两者之间并不直接相互依赖,其耦合也就相应降低。如生产者直接调用消费者的某个方法,由于函数调用是同步的,在消费者的方法没有返回之前,生产者只好一直自我阻塞等待。当消费者消费数据很慢时,生产者就会阻塞很长的时间。
使用了生产者/消费者模式之后,生产者和消费者可以是两个独立的并发主体。生产者把制造出来的数据往缓冲区放入,就可以再去生产下一个数据。基本上不再依赖消费者的处理速度。
针对 Java5 中的阻塞队列(BlockingQueue)的通信则很简单,它隐含的提供了以上的控制,不需要使用 wait 和 nofity 在生产者和消费者之间通信。阻塞队列中,如队列满了,put()方法将自动阻塞,如果队列是空的,take()方法将也将自动阻塞。具体模式和通信方式如图 4-2 所示。
![](https://www.writebug.com/myres/static/uploads/2022/1/15/e9ee4ff2ff123431fb10d5ae6da5ed6a.writebug)
图 4-2 生产者消费者模式与进程通信示意图
### 生产者进程详细设计
采用循环队列的方式进行处理,在 Producer 类中传入循环次数参数,并调用 Staging_Area 类中的方法 produce(),在此进程开始前加锁,独自占有资源,开始生产且不可抢占。在 produce()方法中,使用 LinkedBlockingQueue 中的 put()方法将 Integer 类型的对象放入队列,注意到此时的 put()部分底层源码如下。
```
putLock.lockInterruptibly();
while (count.get() == capacity) {
notFull.await();
}
if (c + 1 < capacity) notFull.signal();
finally {
putLock.unlock();
}
if (c == 0) signalNotEmpty();
```
据此可总结出 put()方法的核心分为四步:
Step1:把数据封装成 Node 节点,获取 put 锁;
Step2:验证队列是否已满,满则阻塞线程;
Step3:如果没有满则把节点加到队列中,count 加 1,并获取加之前的数量;
Step4:如果现在数量还是小于最大容量则唤醒阻塞的 put 线程,如果之前数量是 0 则唤醒 take 线程;
具体生产者算法的流程图如图 4-3 所示。
![](https://www.writebug.com/myres/static/uploads/2022/1/15/828f92cd6794b3c14b8f1f42bae0ae91.writebug)
图 4-3 生产者算法执行流程图
### 消费者进程详细设计
消费者的设计与生产者类似,主要区别在于 take 方法的使用和 sum 的统计。
总结出 take()方法核心同样分为四步:
Step1: 首先获取 take 锁;
Step2: 判断队列中是否有数据,如果没有则阻塞线程;
Step3: 调用 dequeue 方法获取数据,并把 count 减 1;
Step4: 如获取前队列数量大于 1 说明有数据,可唤醒其他 take 线程,如果获取前队列数量等于最大容器数量则说明有可能有阻塞的 put 线程,需要唤醒;
具体消费者算法的流程图如图 4-4 所示。
![](https://www.writebug.com/myres/static/uploads/2022/1/15/b1fb68f67d2b01cc2dcd0a69e3e08dc7.writebug)
图 4-4 消费者算法执行流程图
## 调试分析
(1)在阻塞队列中,对于统计的数字一直无法正确获得和输出,网络上也没有针对阻塞队列统计这方面的资料和解决方法,最后我通过线程的休眠和 take 方
计算机毕设论文
- 粉丝: 1w+
- 资源: 394
最新资源
- 基于CSS与JavaScript的积分系统设计源码
- 生物化学作业_1_生物化学作业资料.pdf
- 基于libgdx引擎的Java开发连连看游戏设计源码
- 基于MobileNetV3的SSD目标检测算法PyTorch实现设计源码
- 基于Java JDK的全面框架设计源码学习项目
- 基于Python黑魔法原理的Python编程技巧设计源码
- 基于Python的EducationCRM管理系统前端设计源码
- 基于Django4.0+Python3.10的在线学习系统Scss设计源码
- 基于activiti6和jeesite4的dreamFlow工作流管理设计源码
- 基于Python实现的简单植物大战僵尸脚本设计源码
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
- 1
- 2
前往页