操作系统实验报告生产者消费者问题Word文档下载推荐.docx
《操作系统实验报告生产者消费者问题Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《操作系统实验报告生产者消费者问题Word文档下载推荐.docx(15页珍藏版)》请在冰点文库上搜索。
指导教师签字:
系主任签字:
指导教师对课程设计的评语
成绩:
年月日
生产者消费者问题
一、设计目的
1、了解信号量的使用
2、加深对信号量机制的理解
3、通过研究Linux的进程机制和信号量实现生产者消费者问题的并发控制.
4、掌握基本的同步互斥算法,理解生产者与消费者模型
5、了解多线程(多进程)的并发执行机制,线程(进程)间的同步与互斥
二、设计要求
1、理解生产者与消费者问题模型,掌握解决问题的算法思想
2、掌握正确使用同步机制的方法
3、每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区的全部内容,当前指针位置和生产者/消费者线程的标识符.
4、生产者和消费者各有两个以上.
5、多个生产者或多个消费者之间须有共享对缓冲区进行操作的函数代码.
三、设计说明(含系统框图和(或)主要算法的流程图)
生产者流程图
消费者流程图
有n个生产者和m个消费者,连接在具有k个单位缓冲区的有界环转缓冲上,故又称有界缓冲问题。
其中Pi和Cj都是并发进程,只要缓冲区未满,生产者进程Pi所生产的产品就可投入缓冲区;
类似地,只要缓冲区非空,消费者进程Cj就可以从缓冲区取走并消耗产品。
生产者——消费者问题是典型的进程同步问题,这些进程必须按照一定的生产率和消费率来访问共享缓冲区,用P、V操作解决生产者和消费者共享单缓冲区的问题,可设置两个信号量empty和full,其初值分别为1和0,empty指示能否向缓冲区放入产品,full指示能否从缓冲区取出产品。
为了使其协调工作,必须使用一个信号量mutex(初值为1),以限制生产者和消费者互斥地对缓冲区进行存取,另用两个信号量empty1(初值为缓冲区大小)和full1(初值为0),以保证生产者不向已满的缓冲区中放入产品,消费者不从空缓冲区中取产品。
生产者功能描述:
在同一个进程地址空间内执行两个线程。
生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。
当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区。
消费者功能描述:
消费者线程从缓冲区获得物品,然后释放缓冲区,当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来。
在实现本程序的生产者消费者模型时,具体地通过以下同步对象实现互斥:
①设一个互斥量Mutex,以实现生产者在查询和保留缓冲区的下一个空位置时进行互斥。
②每一个生产者用一个信号量与消费者同步,通过设置Full实现,该组信号量用于表示相应产品以生产。
同时用一个表示空缓冲区数目的信号量Empty进行类似的同步,指示缓冲区中是否存在空位置,以便开始生产下一个产品。
数据结构及部分函数描述
类SeqSquare:
对类SeqSquare的声明及其中一些函数
classSeqSquare
{
public:
SeqSquare(intn);
~SeqSquare();
voidP(intx);
//p操作
voidV(intx);
//v操作
boolIsEmpty();
//判断是否为空
boolIsFull();
//判断是否已满
voiddeca();
voiddecb();
intgetSize();
intgetmaxSize();
intgettop();
intgeta();
intgetb();
protected:
private:
int*elements;
inttop,a,b,maxSize;
};
说明:
①用动态整型数组*elements来代表缓冲区,不管是生产产品还是对已有产品的消费都需要访问该缓冲区。
②函数IsFull()用于判断缓冲区是否已满,生产者能否使用缓冲区。
③函数IsEmpty()用于判断缓冲区是否为空,消费者能否使用缓冲区。
详细代码
//生产者消费者1.cpp:
Definestheentrypointfortheconsoleapplication.
//
#include"
stdafx.h"
iostream"
usingnamespacestd;
boolSeqSquare:
:
IsEmpty()//判断是否为空
return(top==-1)?
true:
false;
}
IsFull()//判断是否已满
return(top>
=maxSize-1)?
voidSeqSquare:
deca()
a--;
decb()
b--;
intSeqSquare:
getSize()
returntop+1;
getmaxSize()
returnmaxSize;
gettop()
returntop;
geta()
returna;
getb()
returnb;
SeqSquare:
SeqSquare(intn)
top=-1;
a=b=0;
maxSize=n;
elements=newint[maxSize];
P(intx)
if(IsFull()==true)
{
a=a+1;
}
else
elements[++top]=x;
V(intx)
if(IsEmpty()==true)
b=b+1;
x=elements[top--];
voidproducer(SeqSquare*a)//生产者操作
a->
P
(1);
voidconsumer(SeqSquare*a)//消费者操作
V
(1);
~SeqSquare()
deleteelements;
//缓冲区显示
voidshowbuf(SeqSquare*a)
inti=a->
getSize();
intmain()
inti,n;
cout<
<
"
请输入缓冲区大小:
endl;
cin>
>
n;
SeqSquare*s;
s=newSeqSquare(n);
while(i!
=4)
请选择操作:
"
1.生产一件产品;
2.消费一件产品"
3.显示缓冲区;
4.退出系统。
5.需要改变缓冲区大小!
i;
switch(i)
{
case1:
producer(s);
if(s->
geta()==0)
{
cout<
endl<
成功生产一件商品!
}
else
没有空间供生产者生产!
s->
deca();
break;
case2:
consumer(s);
if(s->
getb()==0)
{
cout<
成功消费一件商品!
}
else
没有产品供消费者消费!
case3:
showbuf(s);
cout<
缓冲区已占用:
s->
getSize()<
可用空间为:
(n-s->
getSize())<
case4:
成功退出程序!
case5:
cin>
s=newSeqSquare(n);
缓冲区大小已发生改变,数据已清除!
default:
输入操作不正确,请重新输入!
}
return0;
四、运行结果及分析
(三)结果分析
(1)在每个程序中需要先做P,后做V,二者要成对出现,夹在二者中间的代码段就是该进程的临界区。
(2)对同步信号量full和empty的P,V操作同样必须成对出现,但它们分别位于不同的程序中。
(3)无论在生产者进程中还是消费者进程中,两个P操作的次序不能颠倒:
应先执行同步信号量的P操作,然后执行互斥信号量的P操作。
否则可能造成进程死锁。
五、总结
课程本次设计通过模拟计算机操作系统中经典的“生产者—消费者问题”,巩固了我在操作系统课上所学的知识,加深了对操作系统中进程同步和互斥等问题,完成了多进程同步方法解决生产者-消费者问题全部过程,结果满足设计要求。
设计过程中遇到不少困难,在反复研究老师的PPT及课本的原理后才逐渐明晰怎样将代码实现,虽然这学期学过Java,但java不是很熟悉,因此还是选择C++语言。
以前学习C++没有深入了解到线程这个概念,在学习Java的时候才知道有专门的线程类。
所以我在网上也参考了其他人用C++编写尤其是关于多进程程序的设计实现。
通过本次设计,我较好地掌握了通过研究Linux的进程机制和信号量实现生产者消费者问题的并发控制全过程,尤其是对多进程程序设计方法有了更深的理解,开拓了思路,锻炼了实践动手能手。