生产者与消费者算法实现.docx
《生产者与消费者算法实现.docx》由会员分享,可在线阅读,更多相关《生产者与消费者算法实现.docx(14页珍藏版)》请在冰豆网上搜索。
生产者与消费者算法实现
课程设计说明书
题目:
生产者与消费者算法模拟
院系:
计算机科学与工程
专业班级:
信息安全(xxxx)班
学号:
201130xxxx
学生姓名:
xxxx
指导教师:
xxxx
2013年xx月xx日
xxxx大学课程设计(论文)任务书
计算机院系计算机教研室
学号
20113xxxxx
学生姓名
xxxx
专业(班级)
xxxxx
设计题目
生产者与消费者算法模拟
设
计
技
术
参
数
(1)系统作业或进程的数目;
(2)系统资源的种类和数目;
(3)系统作业或进程的对每类资源的最大需求数目;
(4)系统作业或进程已分配的资源数目。
设
计
要
求
(1)检查系统安全状态:
根据系统作业或进程的对每类资源的最大需求数目、已分配的资源数目等计算是否存在安全序列。
(2)检查系统是否可以继续某个进程资源分配请求。
工
作
量
要求设计说明书的字数在3000字以上。
工
作
计
划
2012.11.25-11.26根据课程设计的要求,查找相关资料,完成需求分析;
2012.11.26-11.27进行系统的概要设计;
2012.11.27-11.28进行系统的详细设计和源代码的书写;
2013.11.29-11.30对系统进行调试分析,写出课程设计报告。
参
考
资
料
[1]CayS.Horstmann,GaryCornell编著.JAVA核心技术卷I.北京:
机械工业出版社,2008.
[2]郑莉编著.Java语言程序设计(第二版).北京:
清华大学出版社,2011.
[3]吕国英等编著.算法设计与分析.北京:
清华大学出版社,2009.
[4]马小军等编.软件工程项目案例与实践指导.北京:
清华大学出版社,2013.
[5]汤子瀛等编著.计算机操作系统.西安:
西安电子科技大学出版社,2011.
指导教师签字
教研室主任签字
2012年xx月xx日
指导教师评语:
成绩:
指导教师:
年月日
xxxx大学课程设计(论文)成绩评定表
1.问题描述
1.1目的
掌握信号的使用方法和P、V操作的定义,掌握使用P、V操作实现进程之间同步与互斥的方法,加深对进程同步互斥概念的理解。
1.2设计要求
设计一程序,由一个进程创建三个子进程,三个子进程一个是生产者进程,两个是消费者进程,且要求:
●父子进程都使用父进程创建的共享存储区进行通信,由生产者进程将一个数组中的十个数值发送到由5个缓冲区组成的共享内存中;
●两个消费者进程轮流接收并输出这十个数值,同时将两个消费者进程读出的数值进行累加求各和。
●考虑生产者进程生产的速度和消费者进程速度。
2.需求分析
生产者--消费者问题是一个著名的进程同步问题。
既然有进程间的同步,也就必将涉及到进程之间的互斥与通信问题,对于这个问题的解决有着很强的现实意义。
它的现实意义在于可以类比到计算机中对于临界资源的互斥共享。
生产者与消费者就好比是对计算机临界资源访问的程序或用户,而临界资源如打印机、磁带机等设备。
3.概要设计
3.1程序流程图
说明:
图3.1程序流程图所示,首先生产者与消费者线程创建,便就去访问缓冲区。
对于生产者若缓冲区没有被其他线程访问,且缓冲区未满则生产数据存放到缓冲区,若其中有一条件没有满足则生产者线程进入阻塞状态。
而对于消费者同样也需要缓冲区没有被其他线程访问,但同时要求缓冲区未空才能从缓冲区取数据,若其中有一个条件为满足则同样进入阻塞状态。
图3.1程序流程图
4.详细设计
4.1程序框架
4.1.1生产者与消费者的父类
publicclassSuperThreadextendsJPanel{
//定义缓冲区的读写锁
privateLockbufferLock;
//共享缓冲区
publicstaticIntBufferbuffer=IntBuffer.allocate(5);
//生产者数组
publicintarray[]={1,5,6,9,8,11,13,10,7,3};
//生产者执行的次数
publicstaticintcount=0;
//两个生产者取出数据的累加
publicstaticintconsumerSum=0;
//记录消费者取数次数
publicstaticintconsumerCount=0;
//存放从缓冲区中取得的数据
privatestaticintconsumerData;
//定义线程名
publicStringnameString;
//线程互斥信号,值为0表示生产者进程,值为1表示消费者进程
publicstaticintmutex=0;
/*构造函数*/
publicSuperThread(Stringname){
//主要完成一些变量的初始化
}
/*获得线程名*/
publicStringgetNameString(){
returnnameString;
}
/*设置线程名*/
publicvoidsetNameString(StringnameString){
this.nameString=nameString;
}
/*获得互斥信号*/
publicstaticintgetMutex(){
returnmutex;
}
/*设置互斥信号*/
publicstaticvoidsetMutex(intmutex){
SuperThread.mutex=mutex;
}
/*判断是否有线程访问缓冲区,没有则对线程进行加锁*/
publicbooleanwait(intmutex){
if(mutex==1){
returnfalse;
}else{
returntrue;
}
}
/*释放进程操作完成信号,其实本质就是修改mutex的信号值*/
publicstaticvoidsignal(){
mutex=0;
}
/*判断缓冲区是否为空*/
publicbooleanisBufferEmpty(){
//根据缓冲区中是否有0存在来判断是否为空
//若0的个数为5则为空,反之则不为空
}
/*判断缓冲区是否为满*/
publicbooleanisBufferFull(){
//根据缓冲区中是否有0存在来判断是否为空
//若0的个数为0则为满,反之则不满
}
/*消费数,即在缓冲区中取数*/
publicvoidconsume(){
if(wait(mutex)&&!
isBufferEmpty()){//判断是否访问缓冲区
//加锁
bufferLock.lock();
try{
//设置互斥信号
//从缓冲区取数
//将取数后的缓冲区置0
//释放互斥信号
}finally{
//解锁
bufferLock.unlock();
}
}
}
/*消费者取得缓冲区数据*/
publicintgetBufferData(intindex){
//完成取数操作
returndata;
}
/*生产数,即向缓冲区中存数*/
publicvoidproduce(){
if(wait(mutex)&&!
isBufferFull()){//判断是否访问缓冲区
bufferLock.lock();//加锁
try{
//设置互斥信号
//向缓冲区存数
//释放互斥信号
}finally{
//解锁
bufferLock.unlock();
}
}
}
/*生产者向公共缓冲区放数据*/
publicvoidputBufferData(intindex){
//完成想缓冲区存数操作
}
}
4.1.2生产者类
publicclassProducerextendsSuperThreadimplementsRunnable{
//生产者休眠时间
privateintproducerDelay;
/*生产者构造函数*/
publicProducer(Stringname){
super(name);
}
/*获得生产者休眠时间*/
publicintgetProducerDelay(){
returnproducerDelay;
}
/*设置生产者休眠时间*/
publicvoidsetProducerDelay(intproducerDelay){
this.producerDelay=producerDelay;
}
/*线程中的run函数,线程启动时默认调用的函数*/
@Override
publicvoidrun(){
//线程启动后向缓冲区存数操作
}
}
4.1.3消费者类
publicclassConsumerextendsSuperThreadimplementsRunnable{
/*消费者休眠时间*/
privateintconsumerDelay;
/*消费者构造函数*/
publicConsumer(Stringname){
super(name);
}
/*获得消费者休眠时间*/
publicintgetConsumerDelay(){
returnconsumerDelay;
}
/*设置消费者休眠时间*/
publicvoidsetConsumerDelay(intconsumerDelay){
this.consumerDelay=consumerDelay;
}
/*线程中的run函数,线程启动时默认调用的函数*/
@Override
publicvoidrun(){
while(true){
//线程启动后向缓冲区取数操作
}
}
4.1.4主程序入口
主函数main(String[]args){
//生产者与消费者对象定义producer、consumer1、consumer2
//设置休眠参数,如1000、2000、2500
//创建线程producerThread、consumer1Thread、consumer2Thread
//启动线程producerThread.start()、consumer1Thread.start()、
//consumer2Thread.start();
}
4.2基本算法分析
4.2.1wait(mutex)与signal()数值信号
数值信号wait(mutex)主要是通过整型值mutex的设置来表示缓冲区是否已被访问,具体过程为:
当有线程需要访问缓冲区时,先确定wait(mutex)信号值,若mutex的值为1则wait(mutex)为真,便可进行下一步操作,若mutex的值为0则wait(mutex)为不为真,该线程阻塞。
当线程完成对缓冲区的访问后需要调用signal()信号对信号值mutex进行释放,释放后mutex的值为1,以便其他线程能够访问缓冲区。
wait(mutex)与signal()的主要代码如下:
publicbooleanwait(intmutex){//wait(mutex)信号
if(mutex==1){
returnfalse;
}else{
returntrue;
}
}
publicstaticvoidsignal(){//signal()信号
mutex=0;
}
4.2.2isBufferEmpty()与isBufferFull()信号
对于以上所述的wait(mutex)信号还不足以控制线程之间的同步与互斥,还必须使用到isBufferEmpty()与isBufferFull()两个信号。
对于生产者要用到信号isBufferFull()来判断缓冲区是否为满,当wait(mutex)型号值为真且isBufferFull()信号值不为真时,生产者线程才能对缓冲区进行存数操作,否则就阻塞等待机会。
而对于消费者同样也要用到辅助信号isBufferEmpty()来判断缓冲区是否为空,只有缓冲区不为空且wait(mutex)为真是,消费者才能对缓冲区进行取数操作。
isBufferEmpty()与isBufferFull()的主要代码如下:
publicbooleanisBufferEmpty(){//判断缓冲区是否为空
intcount=0;
for(inti=0;iif(buffer.get(i)==0){//根据缓冲区中的0的个数来判断,若缓
//区0的个数为5(缓冲区容量为5),则为空//反之不为空
count++;
}
}
if(count==5){
returntrue;
}else{
returnfalse;
}
}
publicbooleanisBufferFull(){//判断缓冲区是否为满
intcount=0;
for(inti=0;iif(buffer.get(i)!
=0){//根据缓冲区中不为0的个数来判断,若缓
//区不为0的个数小于5(缓冲区容量为5),//则不为满,反之为满
count++;
}
}
if(count<5){
returnfalse;
}else{
returntrue;
}
}
4.2.3produce()存数方法与consume()取数方法
produce()方法由生产者使用,在条件满足的情况下对缓冲区进行存数操作,而这个条件就是wait(mutex)==true&&!
isBufferFull()==true。
对于消费者调用consume()方法同样也要满足这样一个条件:
wait(mutex)==true&&!
isBufferEmpty()==true。
produce()与consume()方法的主要代码如下:
/*生产数,即向缓冲区中存数*/
publicvoidproduce(){
if(wait(mutex)&&!
isBufferFull()){
bufferLock.lock();//对该程序段加锁,防止其他线程访问缓冲区
try{
setMutex
(1);//将线程互斥信号值mutex设置为1,使之互斥
intindex=0;
for(inti=0;iif(buffer.get(i)==0){
index=i;
break;
}
}
putBufferData(index);//向缓冲区中存入数据
signal();//释放互斥信号,将mutex设置为0
}finally{
bufferLock.unlock();//解锁
}
}
}
/*消费数,即在缓冲区中取数*/
publicvoidconsume(){
if(wait(mutex)&&!
isBufferEmpty()){
bufferLock.lock();//对该程序段加锁,防止其他线程访问缓冲区
try{
setMutex
(1);//将线程互斥信号值mutex设置为1,使之互斥
intindex=0;//存放顺序查找第一个为0的数的下摆
inti;
for(i=0;iif(buffer.get(i)==0){
index=i;
break;
}elseif(buffer.get(4)>0){//缓冲区为满的情况
index=5;
}
}
consumerData=getBufferData(index-1);//取数据
consumerCount++;
if(consumerCount<=2){
consumerSum=consumerSum+consumerData;//计算两次取数//之和
if(consumerCount==2){
System.out.println("消费者取数之和为:
"+consumerSum);
consumerSum=0;