生产者消费者问题.docx
- 文档编号:3840574
- 上传时间:2022-11-25
- 格式:DOCX
- 页数:11
- 大小:154.06KB
生产者消费者问题.docx
《生产者消费者问题.docx》由会员分享,可在线阅读,更多相关《生产者消费者问题.docx(11页珍藏版)》请在冰豆网上搜索。
生产者消费者问题
课程设计报告
课程名:
操作系统
专业
学生姓名
班级
学号
指导教师
完成日期
博雅学院
“操作系统”课程设计报告
——生产者-消费者问题的模拟实现
1.课程设计的目的
本课程设计是学习完“操作系统原理”课程后进行的一次全面的综合训练,通过课程设计,更好地掌握操作系统的原理及实现方法,加深对操作系统基础理论和重要算法的理解,加强学生的动手能力。
2.设计内容
2.1概述
用多进程同步方法解决生产者-消费者问题,C或C++语言实现。
通过研究Linux的进程机制和信号量实现生产者消费者问题的并发控制。
说明:
有界缓冲区内设有20个存储单元,放入/取出的数据项设定为1-20这20个整型数。
设计要求:
(1)每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区的全部内容,当前指针位置和生产者/消费者县城的标识符。
(2)生产者和消费者各有两个以上。
(3)多个生产者或多个消费者之间须有共享对缓冲区进行操作的函数代码。
2.2设计原理
多进程是一种非常简洁的多任务操作方式。
在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种烦琐的多任务工作方式。
生产者-消费者方案是多进程应用程序开发中最常用的构造之一。
因此困难也在于此。
因为在一个应用程序中可以多次重复生产者-消费者行为,其代码也可以如此。
设计中创建了Consumer类,该类通过在一些多进程应用程序中促进代码重用以及简化代码调试和维护来解决这个问题。
多进程应用程序通常利用生产者-消费者编程方案,其中由生产者进程创建重复性作业,将其传递给作业队列,然后由消费者进程处理作业。
多进程是一种使应用程序能同时处理多个操作的编程技术。
通常有两种不同类型的多进程操作使用多个进程:
适时事件,当作业必须在特定的时间或在特定的间隔内调度执行时;后台处理,当后台事件必须与当前执行流并行处理或执行时;适时事件的示例包括程序提醒、超时事件以及诸如轮询和刷新之类的重复性操作。
后台处理的示例包括等待发送的包或等待处理的已接收的消息。
生产者-消费者方案很适合于后台处理类别的情况。
这些情况通常围绕一个作业“生产者”方和一个作业“消费者”方。
当然,关于作业并行执行还有其它考虑事项。
在大多数情况下,对于使用同一资源的作业,应以FCFS的方式按顺序处理,这可以通过使用单进程的消费者轻松实现。
通过使用这种方法,使用单个进程来访问单个资源,而不是用多个进程来访问单个资源。
要启用标准消费者,当作业到来时创建一个作业队列来存储所有作业。
生产者进程通过将新对象添加到消费者队列来交付这个要处理的新对象。
然后消费者进程从队列取出每个对象,并依次处理。
当队列为空时,消费者进入休眠。
当新的对象添加到空队列时,消费者会醒来并处理该对象。
2.3详细设计及编码
(1)调试问题分析
为解决生产者/消费者问题,应该设置两个资源信号量,其中一个表示空缓冲区的数目,用Full表示,其初始值为有界缓冲区的大小BUFFER_NUM;另一个表示缓冲区中产品的数目,用Empty表示,其初始值为0。
另外,由于有界缓冲区是一个临界资源,必须互斥使用,所以还需要再设置一个互斥信号量Mutex,起初值为1。
在生产者/消费者问题中,信号量实现两种功能。
首先,它是生产产品和消费产品的计数器,计数器的初始值是可利用的资源数目(有界缓冲区的长度)。
其次,它是确保产品的生产者和消费者之间动作同步的同步器。
生产者要生产一个产品时,首先对资源信号量Full和互斥信号量Mutex进行P操作,申请资源。
如果可以通过的话,就生产一个产品,并把产品送入缓冲区。
然后对互斥信号量Mutex和资源信号量Empty进行V操作,释放资源。
消费者要消费一个产品时,首先对资源信号量Empty和互斥信号量Mutex进行P操作,申请资源。
如果可以通过的话,就从缓冲区取出一个产品并消费掉。
然后对互斥信号量Mutex和资源信号量Full进行V操作,释放资源。
如果缓冲区中已经没有可用资源,就把申请资源的进程添加到等待队列的队尾。
如果有一个资源被释放,在等待队列中的第一个进程被唤醒并取得这个资源的使用权。
(2)流程图
图2-1生产者流程图
图2-2消费者流程图
(3)源程序
#include
#include
#include
#include
typedefHANDLESemaphore;//信号量的Windows原型
#defineP(S)WaitForSingleObject(S,INFINITE)//定义Windows下的P操作
#defineV(S)ReleaseSemaphore(S,1,NULL)//定义Windows下的V操作
#definerate1000
#defineCONSUMER_NUM2/*消费者个数*/
#definePRODUCER_NUM3/*生产者个数*/
#defineBUFFER_NUM20/*缓冲区个数*/
char*thing[8]={"豆浆","油条","烧饼","牛奶","包子","烧卖","煎蛋","雪碧"};//生产和消费的产品名称
structBuffer
{
intproduct[BUFFER_NUM];//缓冲区
intstart,end;//两个指针相当于教材中的inout指针
}g_buf;
SemaphoreEmpty,Full,Mutex;//分别相当于Empty,Full,Mutex三个信号量
/**************消费者线程*****************************/
DWORDWINAPIConsumer(LPVOIDpara)
{
//i表示第i个消费者
inti=*(int*)para;//利用para传入当前消费者的编号
intptr;//待消费的内容的指针
printf("消费者%1d:
需要资源\n",i);
intj=0;
while(j++<4){
//等待产品
P(Full);
//有产品,先锁住缓冲区
P(Mutex);
//记录消费的物品
ptr=g_buf.start;
//再移动缓冲区指针
g_buf.start=(g_buf.start+1)%BUFFER_NUM;
//让其他消费者或生产者使用
printf("消费者%01d:
我需要buf[%d]=%s\n",i,ptr,thing[g_buf.product[ptr]]);
//消费完毕,并释放一个缓冲
printf("消费者%01d:
我消费完毕%s\n",i,thing[g_buf.product[ptr]]);
V(Mutex);
V(Empty);
Sleep(rate*rand()%10+110);
}
return0;
}
/****************生产者线程********************************/
DWORDWINAPIProducer(LPVOIDpara)
{
inti=*(int*)para-CONSUMER_NUM;
intptr;
intdata;//产品
intj=0;
while(j++<4)
{
data=rand()%8;
printf("生产者%01d:
生产出:
%s!
\n",i,thing[data]);
//等待存放空间
P(Empty);
//有地方,先锁住缓冲区
P(Mutex);
//记录消费的物品
ptr=g_buf.end;
//再移动缓冲区指针
g_buf.end=(g_buf.end+1)%BUFFER_NUM;
printf("生产者%01d:
放到缓冲区buf[%d]=%s\n",i,ptr,thing[data]);
g_buf.product[ptr]=data;
//放好了完毕,释放一个产品
//让其他消费者或生产者使用
V(Mutex);
V(Full);
Sleep(rate/2*rand()%10+110);
}
return0;
}
intmain(intargc,char*argv[])
{
//线程技术,前面为消费者线程,后面为生产者线程
HANDLEhThread[CONSUMER_NUM+PRODUCER_NUM];//线程计数
srand(time(NULL));
rand();
DWORDtid;
inti=0;
//初始化信号量
Mutex=CreateSemaphore(NULL,1,1,"MutexOfConsumerAndProducer");
Empty=CreateSemaphore(NULL,BUFFER_NUM,BUFFER_NUM,"BufferSemaphone");
Full=CreateSemaphore(NULL,0,BUFFER_NUM,"ProductSemaphone");
if(!
Empty||!
Full||!
Mutex)
{
printf("CreateSemaphoneError!
\n");
return-1;
}
inttotalThreads=CONSUMER_NUM+PRODUCER_NUM;
//开启消费者线程
printf("先请消费者上席!
\n");
for(i=0;i { hThread[i]=CreateThread(NULL,0,Consumer,&i,0,&tid); if(hThread[i])WaitForSingleObject(hThread[i],10); } printf("生产者就位! \n"); for(;i { hThread[i]=CreateThread(NULL,0,Producer,&i,0,&tid); if(hThread[i])WaitForSingleObject(hThread[i],10); } //生产者和消费者的执行 WaitForMultipleObjects(totalThreads,hThread,TRUE,INFINITE); return0; } 3结果及分析 4设计小结 本次课程设计通过模拟计算机操作系统中经典的“生产者—消费者问题”,巩固了我在操作系统原理课上所学的知识,加深了对操作系统中进程同步和互斥等问题,完成了多进程同步方法解决生产者-消费者问题全部过程,结果满足设计要求。 设计过程中遇到不少困难,在反复研究老师的PPT及课本的原理后才逐渐明晰怎样将代码实现,虽然这学期学过Java,但java不是很熟悉,因此还是选择C++语言。 以前学习C++没有深入了解到线程这个概念,在学习Java的时候才知道有专门的线程类。 所以我在网上也参考了其他人用C++编写尤其是关于多进程程序的设计实现。 在代码的实现过程中,我是主要定义了两个函数DWORDWINAPIConsumer(LPVOIDpara)和DWORDWINAPIProducer(LPVOIDpara),在这两个函数中实现PV操作。 通过本次设计,我较好地掌握了通过研究Linux的进程机制和信号量实现生产者消费者问题的并发控制全过程,尤其是对多进程程序设计方法有了更深的理解,开拓了思路,锻炼了实践动手能手。 但是我觉得课程设计的时间有点短,中间又夹杂着好几场考试,所以没能做出界面以便于直观的观察出详细过程,只是用代码实现了要描述的功能且达到了要求,所以改进的空间还比较大。 5参考文献 [1]汤子瀛.《计算机操作系统》(修订版).西安电子科技大学出版社,2001。 [2]计算机操作系统教程.孙钟秀等编著.高等教育出版社,2010年8月出版 [3]数据结构教程.李春葆等编著清华大学出版社.2009年4月 [4]面向对象程序设计与VisualC++6.0教程陈天华编著清华大学出版社.2009年7月
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 生产者 消费者 问题
![提示](https://static.bdocx.com/images/bang_tan.gif)