课程设计课程名称计算机操作系统题目名称生产者消费者同步算法专业班级学生姓名学号指导教师二○一五年十二月一日目录一、系统总体方案 (1)(一)目的 (1)(二)问题 (1)(三)主要完成的任务 (1)(四)使用的开发工具 (1)(五)解决的主要问题 (1)二、设计思路和主要步骤 (2)(一)多道程序 (2)(二)进程 (2)(三)线程 (2)(四)同步和互斥的概念 (3)三、各功能模块和流程图 (3)四、设计代码 (5)(一)UI界面主线程 (5)(二)管程类 (7)(三)生产者类 (8)(四)消费者类 (9)五、运行效果截图 (10)六、心得体会和参考资料 (11)(一)心得体会 (11)(二)参考资料 (11)蚌埠学院计算机科学与技术系课程设计任务书一、系统总体方案(一)目的根据进程同步机制,编写一个解决下述问题的程序,可显示缓冲池状态、放数据、取数据等过程。
(二)问题一组生产者向一组消费者提供消息,它们共享一个有界缓冲池,生产者向其中投放消息,消费者从中取得消息。
假定这些生产者和消费者互相等效,只要缓冲池未满,生产者可将消息送入缓冲池;只要缓冲池未空,消费者可从缓冲池取走一个消息。
(三)主要完成的任务通过多线程编程实现生产者消费者同步算法。
(四)使用的开发工具Eclipse,语言Java(五)解决的主要问题上述(二)中问题。
二、设计思路和主要步骤(一)多道程序多道程序设计是指在主存中同时存放多道用户作业,使它们都处于执行的开始点和开始点之间,这些程序共享计算机系统资源。
多道程序设计的主要优点有:提高CPU的利用率。
在多道程序环境下,多个程序共享计算机资源当某个程序等待I/O 操作时,CPU可以执行其他程序,大大提高CPU的利用率。
提高设备的利用率。
在多道程序环境下,多个程序共享系统的设备,大大提高系统设备的利用率。
提高系统的吞吐量。
在多道程序环境下,减少了程序的等待时间,提高了系统的吞吐量。
(二)进程进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。
它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。
(三)线程线程,有时被称为轻量级进程(Lightweight Process,L WP),是程序执行流的最小单元。
一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。
另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。
一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。
由于线程之间的相互制约,致使线程在运行中呈现出间断性。
线程也有就绪、阻塞和运行三种基本状态。
每一个程序都至少有一个线程,那就是程序本身。
(四)同步和互斥的概念进程互斥是进程之间发生的一种间接性作用,一般是程序不希望的。
通常的情况是两个或两个以上的进程需要同时访问某个共享变量。
我们一般将发生能够问共享变量的程序段成为临界区。
两个进程不能同时进入临界区,否则就会导致数据的不一致,产生与时间有关的错误。
解决互斥问题应该满足互斥和公平两个原则,即任意时刻只能允许一个进程处于同一共享变量的临界区,而且不能让任一进程无限期地等待。
互斥问题可以用硬件方法解决,我们不作展开;也可以用软件方法,这将会在本讲详细介绍。
同步是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。
在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。
少数情况是指可以允许多个访问者同时访问资源。
三、各功能模块和流程图基本的技术路线:面向对象软件的总体结构、模块关系、总体流程;(一)功能模块总体分为4个模块:●用户图形界面模块UI.java●消费者Consumer.java●生产者Producer.java●管程Pool.java(二)流程图否否开始四、设计代码总体执行过程是:输入参数、点击设置使之生效、然后点击开始(一)UI界面主线程里面有几个重要的属性;private int CustomerSize; //消费者的数量private int ProducerSize; //生产者的数量private int PoolSize; //缓冲区大小public Pool pool; //管城对象public int buySpeed; //消费间隔,控制消费速度public int produceSpeed; //生产间隔,控制生产速度public long inProductCount=0; //已经生产产品的数量public long outProductCount=0; //已经消费的产品数量public long currentProductCount=0; //当前的产品数量public boolean isStop=false; //强制线程退出的信号量这些属性是在点击界面的设置按钮后把用户输入的参数进行相应的赋值。
当点击开始按钮后执行下面的主要代码://一些必要的初始化isStop=false;inProductCount=0;outProductCount=0;currentProductCount=0;this.pool=new Pool(this);//初始化管程this.pool.MAX_SIZE=this.PoolSize;//设置仓库大小//开启消费者线程和生产者线程//启动线程同时把ui界面对象传递到线程中,使线程获得必要的设置信息for(int i=0;i<this.CustomerSize;i++){new Thread(new Customer(this)).start();}for(int i=0;i<this.ProducerSize;i++){new Thread(new Producer(this)).start();}消费者和生产者的同步和他们各自之间的互斥都是在管程里面实现的.(二)管程类import java.util.Date;import java.util.Stack;public class Pool {private Stack<Integer> products;//用一个栈模拟一个缓冲区public int MAX_SIZE; //栈能到达的最大值private UI ui; //接收转递进来的ui对象,以实现操作界面显示相关信息public Pool(UI ui){this.ui=ui;this.products=new Stack<Integer>();}public synchronized void getProduct(){//synchronized实现了消费者线程间的互斥保证同一时刻只能有一个线程调用该方法while(this.products.isEmpty()){//products是一个栈结构通过判断它的空实现消费者线程和生产者线程之间的同步try {wait();//栈是空的,不能取数据,线程等待} catch (InterruptedException e) {e.printStackTrace();}}int product;product=products.pop();//栈没有空,取数据ui.addInfo("消费者【"+Thread.currentThread().getId()+"】从仓库取出产品【"+product+"】成功。
当前库存量【"+products.size()+"】" +"---当前时间戳:"+new Date().getTime());ui.outProductCount++;ui.currentProductCount=products.size();ui.refreshStatus();notifyAll();//取完数据同时生产线程生产产品}public synchronized void setProduct(){//synchronized实现了生产者线程间的互斥保证同一时刻只能有一个线程调用该方法int product=(int)(Math.random()*10000);while(this.products.size()==MAX_SIZE){//products是一个栈结构通过判断它的满实现消费者线程和生产者线程之间的同步try {wait();//栈满了,不能继续生产,线程等待} catch (InterruptedException e) {e.printStackTrace();}}this.products.push(product);//栈没有满,继续生产ui.addInfo("生产者【"+Thread.currentThread().getId()+"】将产品【"+product+"】放入仓库。
当前库存量【"+products.size()+"】" +"---当前时间戳:"+new Date().getTime());ui.inProductCount++;ui.currentProductCount=products.size();ui.refreshStatus();notifyAll();//生产完毕,通知消费者消费}}(三)生产者类import java.util.Date;public class Producer implements Runnable{UI ui;public Producer(UI ui){this.ui=ui;//接收传递进来的界面对象,以实现在线程中操作界面显示信息}public void run() {while(!ui.isStop) {//如果信号量ui.isStop是false则一直消费下去,否则退出循环线程自然消亡ui.pool.setProduct();//调用管程生产方法生产产品try {Thread.currentThread().sleep(ui.produceSpeed);} catch (InterruptedException e) {e.printStackTrace();}}//线程退出前在界面中提示本线程退出ui.addInfo("生产者【"+Thread.currentThread().getId()+"】停止生产成功." +"---当前时间戳:"+new Date().getTime());}}(四)消费者类import java.util.Date;public class Customer implements Runnable{UI ui;public Customer(UI ui){this.ui=ui;}public void run() {while (!ui.isStop) {ui.pool.getProduct();//调用管程的消费方法消费产品try {Thread.currentThread().sleep(ui.buySpeed);} catch (InterruptedException e) {e.printStackTrace();}}ui.addInfo("消费者"+Thread.currentThread().getId()+"停止购物成功." +"---当前时间戳:"+new Date().getTime());}}五、运行效果截图六、心得体会和参考资料(一)心得体会通过本次课程设,使我对线程(进程)之间的同步和互斥有了非常直观的理解,学会了通过信号量去解决类似的互斥和同步问题,提高了我的编程解决问题的能力,在代码设计阶段我学到了很多控制线程的技巧,以及线程之间的简单通信。