生产者与消费者问题的模拟实现.docx

上传人:b****6 文档编号:16222056 上传时间:2023-07-11 格式:DOCX 页数:19 大小:82.95KB
下载 相关 举报
生产者与消费者问题的模拟实现.docx_第1页
第1页 / 共19页
生产者与消费者问题的模拟实现.docx_第2页
第2页 / 共19页
生产者与消费者问题的模拟实现.docx_第3页
第3页 / 共19页
生产者与消费者问题的模拟实现.docx_第4页
第4页 / 共19页
生产者与消费者问题的模拟实现.docx_第5页
第5页 / 共19页
生产者与消费者问题的模拟实现.docx_第6页
第6页 / 共19页
生产者与消费者问题的模拟实现.docx_第7页
第7页 / 共19页
生产者与消费者问题的模拟实现.docx_第8页
第8页 / 共19页
生产者与消费者问题的模拟实现.docx_第9页
第9页 / 共19页
生产者与消费者问题的模拟实现.docx_第10页
第10页 / 共19页
生产者与消费者问题的模拟实现.docx_第11页
第11页 / 共19页
生产者与消费者问题的模拟实现.docx_第12页
第12页 / 共19页
生产者与消费者问题的模拟实现.docx_第13页
第13页 / 共19页
生产者与消费者问题的模拟实现.docx_第14页
第14页 / 共19页
生产者与消费者问题的模拟实现.docx_第15页
第15页 / 共19页
生产者与消费者问题的模拟实现.docx_第16页
第16页 / 共19页
生产者与消费者问题的模拟实现.docx_第17页
第17页 / 共19页
生产者与消费者问题的模拟实现.docx_第18页
第18页 / 共19页
生产者与消费者问题的模拟实现.docx_第19页
第19页 / 共19页
亲,该文档总共19页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

生产者与消费者问题的模拟实现.docx

《生产者与消费者问题的模拟实现.docx》由会员分享,可在线阅读,更多相关《生产者与消费者问题的模拟实现.docx(19页珍藏版)》请在冰点文库上搜索。

生产者与消费者问题的模拟实现.docx

生产者与消费者问题的模拟实现

操作系统

课程设计报告

专业

计算机科学与技术

学生姓名

郑伟

班级

BM计算机091

学号

0951401123

指导教师

李先锋

完成日期

2011年12月31日

博雅学院

题目:

生产者与消费者问题的模拟实现

一、设计目的

本课程设计是学习完“操作系统原理”课程后进行的一次全面的综合训练,通过课程设计,更好地掌握操作系统的原理及实现方法,加深对操作系统基础理论和重要算法的理解,加强学生的动手能力。

二、设计内容

1)概述

用多进程同步方法解决生产者-消费者问题,C或C++语言实现。

设计目的:

通过研究Linux的进程机制和信号量实现生产者消费者问题的并发控制。

说明:

有界缓冲区内设有20个存储单元,放入/取出的数据项设定为1-20这20个整型数。

设计要求:

(1)每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区的全部内容,当前指针位置和生产者/消费者县城的标识符。

(2)生产者和消费者各有两个以上。

(3)多个生产者或多个消费者之间须有共享对缓冲区进行操作的函数代码。

(提示:

有界缓冲区可用数组实现)

2)设计原理

计算机系统中的每个进程都可以消费或生产某类资源。

当系统中某一进程使用某一资源时,可以看作是消耗,且该进程称为消费者。

而当某个进程释放资源时,则它就相当一个生产者。

因为有多个缓冲区,所以生产者线程没有必要在生成新的数据之前等待最后一个数据被消费者线程处理完毕。

同样,消费者线程并不一定每次只能处理一个数据。

在多缓冲区机制下,线程之间不必互相等待形成死锁,因而提高了效率。

多个缓冲区就好像使用一条传送带替代托架,传送带上一次可以放多个产品。

生产者在缓冲区尾加入数据,而消费者则在缓冲区头读取数据。

当缓冲区满的时候,缓冲区就上锁并等待消费者线程读取数据;每一个生产或消费动作使得传送带向前移动一个单位,因而,消费者线程读取数据的顺序和数据产生顺序是相同的。

可以引入一个count计数器来表示已经被使用的缓冲区数量。

用hNotEmptyEvent和NotFullEvent来同步生产者和消费者线程。

每当生产者线程发现缓冲区满(count=BufferSize),它就等待hNotEmptyEvent事件。

同样,当消费者线程发现缓冲区空,它就开始等待hNotEmptyEvent。

生产者线程写入一个新的数据之后,就立刻发出hNotEmptyEvent来唤醒正在等待的消费者线程;消费者线程在读取一个数据之后,就发出hNotFullEvent来唤醒正在等待的生产者线程。

通过一个有界缓冲区(用数组来实现,类似循环队列)把生产者和消费者联系起来。

假定生产者和消费者的优先级是相同的,只要缓冲区未满,生产者就可以生产产品并将产品送入缓冲区。

类似地,只要缓冲区未空,消费者就可以从缓冲区中去走产品并消费它。

应该禁止生产者向满的缓冲区送入产品,同时也应该禁止消费者从空的缓冲区中取出产品,这一机制有生产者线程和消费者线程之间的互斥关系来实现。

为解决生产者/消费者问题,应该设置两个资源信号量,其中一个表示空缓冲区的数目,用g_hFullSemaphore表示,其初始值为有界缓冲区的大小SIZE_OF_BUFFER;另一个表示缓冲区中产品的数目,用g_hEmptySemaphore表示,其初始值为0。

另外,由于有界缓冲区是一个临界资源,必须互斥使用,所以还需要再设置一个互斥信号量g_hMutex,起初值为1。

在生产者/消费者问题中,信号量实现两种功能。

首先,它是生产产品和消费产品的计数器,计数器的初始值是可利用的资源数目(有界缓冲区的长度)。

其次,它是确保产品的生产者和消费者之间动作同步的同步器。

生产者要生产一个产品时,首先对资源信号量g_hFullSemaphore和互斥信号量g_hMutex进行P操作,申请资源。

如果可以通过的话,就生产一个产品,并把产品送入缓冲区。

然后对互斥信号量g_hMutex和资源信号量g_hEmptySemaphore进行V操作,释放资源。

消费者要消费一个产品时,首先对资源信号量g_hEmptySemaphore和互斥信号量g_hMutex进行P操作,申请资源。

如果可以通过的话,就从缓冲区取出一个产品并消费掉。

然后对互斥信号量g_hMutex和资源信号量g_hFullSemaphore进行V操作,释放资源。

如果缓冲区中已经没有可用资源,就把申请资源的进程添加到等待队列的队尾。

如果有一个资源被释放,在等待队列中的第一个进程被唤醒并取得这个资源的使用权。

3)详细设计及编码

生产者流程图:

线程自我阻塞

添加到等待队列

唤醒队头的消费线程

唤醒队头的消费线程

生产者线程开始

资源信号量p操作

通过

互斥信号p操作

通过

生产一个产品

把产品送入缓冲区

互斥信号量v操作

等待队列中有消费者进程

资源信号量v操作

等待队列中有消费者进程

Y

Y

N

N

线程自我阻塞

添加到等待队列

未通过

未通过

生产者线程结束

 

 

消费者流程图:

线程自我阻塞

添加到等待队列

唤醒队头的消费线程

唤醒队头的消费线程

消费者线程开始

资源信号量p操作

通过

互斥信号p操作

通过

生产一个产品

把产品送入缓冲区

互斥信号量v操作

等待队列中有消费者进程

资源信号量v操作

等待队列中有消费者进程

Y

Y

N

N

线程自我阻塞

添加到等待队列

未通过

未通过

消费者线程结束

 

数据结构及信号量定义的说明;

#defineSize20

structhuan{

intisHave;//标记缓冲区是否有内容,有内容时,消费者才可以使用,

//没内容时,生产者才可以往缓冲区内写东西

//0表示没有内容,1表示有内容

intjud;//标志缓冲区是否在被使用中,0代表未被使用,1表示使用中

intcontext;//缓冲的内容

};

描叙生产者或消费者:

structperson{

intend;//记录是否完成任务,0表示完成,1表示未完成任务

char*name;/*线程名*/

pthread_tthread;/*线程句柄*/

};

 

4)结果及分析

1、运行示例

在c++中运行源程序,程序主界面截图:

按回车及申请资源和缓冲区进行p操作和申请互斥信号量。

按回车后截图,开始生产产品,产品数量增加1,缓冲区中产品数量也增加1

当产品数量超过4时则停止生产执行v操作,进行消费者生产线程,即开始消费一个产品,当消费了一个产品时产品数量小于4则将消费者线程惊醒v操作开始

生产者线程,如此循环,当用户按回车后这对所有的线程进行v操作,即停止所有的操作。

分析:

生产者线程和消费者线程是2个互斥量,即2个线程只能有一进行操作,生产的产品的数量不能超过4个当小于4时择进行消费者线程。

5)设计小结

在生产者与消费者问题的算法编写程序的时候要尽可能用全所学到的函数,因为这是检测我们用C语言进行程序设计的能力的重要方式。

在编写程序的时候我们不可能一次就成功,往往一个图形要修改甚至是十几次数据才能得到预期的结果。

因此在编写程序的时候一定不能急躁,要耐心地检测输入的数据和输出的结果,在没达到预期目的的情况下,要及时修改数据进行下一次的检测,只有这样才能成功地用C语言编写出需要的程序。

编写程序是一个长期的过程,因此不能急躁,要坐的住。

由于对C语言知识已经有些遗忘,所以我找出了以前的笔记,花了半天的时间去回忆和理解。

对操作系统有关消费者---生产者问题的含义也已经有点模糊,我花了一天的时间看教材,还到图书馆借阅了相关的资料,才开始编程。

刚开始对如何动态实现消费者---生产者问题一筹莫展,于是和一些同学就这个问题讨论过,但是没什么好的效果。

编写程序有的时候需要的就是灵感,因此当有灵感的时候就要开始做,而不能等,必须在灵感未消失前付诸行动,所以才有了凌晨两点才最后做完大型作业。

虽然很累,但是觉得值得。

6)参考文献

【1】汤子瀛等.计算机操作系统.西安电子科技大学出版社.2007年2月

【2】张尧学等编著,计算机操作系统教程,清华出版社。

2002.2

【3】严蔚敏,吴伟民编著,数据结构,清华大学出版社。

2002

【4】陈向群编著,操作系统教程,北京大学出版社,2001.07

【5】郑莉等编著,C++语言设计。

北京:

清华大学出版社.2000

 

三、附录(源程序)

#include

#include

constunsignedshortSIZE_OF_BUFFER=20;//有界缓冲区长度

intg_buffer[SIZE_OF_BUFFER];//开辟缓冲区,用数组表示,可以看成是一个循环队列

unsignedshortProductID=0;//新生产出来的产品的产品号

unsignedshortConsumeID=0;//被消耗的产品的产品号

unsignedshortin=0;//产品进缓冲区时的缓冲区下标,用于记录生产者的指针位置

unsignedshortout=0;//产品出缓冲区时的缓冲区下标,用于记录消费者的指针位置

boolg_continue=1;//控制程序运行:

1表示继续运行,0表示停止运行

HANDLEg_hMutex;//线程间的互斥信号量

HANDLEg_hFullSemaphore;//资源信号量:

缓冲区满

HANDLEg_hEmptySemaphore;//资源信号量:

缓冲区空

DWORDWINAPIProducer(LPVOID);//生产者线程

DWORDWINAPIConsumer(LPVOID);//消费者线程

constunsignedshortPRODUCERS_COUNT=4;//生产者的个数

constunsignedshortCONSUMERS_COUNT=3;//消费者的个数

constunsignedshortTHREADS_COUNT=PRODUCERS_COUNT+CONSUMERS_COUNT;//总线程数

HANDLEhThreads[PRODUCERS_COUNT];//各线程的handle

DWORDproducerID[CONSUMERS_COUNT];//生产者线程的标识符

DWORDconsumerID[THREADS_COUNT];//消费者线程的标识符

/*----------------------------程序提示信息开始------------------------------*/

voidinfo()//程序提示信息

{

std:

:

cout<<"*-----------------------*"<

:

endl;

std:

:

cout<<"|题目:

生产者消费者问题|"<

:

endl;

std:

:

cout<<"|指导老师:

李先锋|"<

:

endl;

std:

:

cout<<"|作者:

郑伟|"<

:

endl;

std:

:

cout<<"|代码行数:

200+|"<

:

endl;

std:

:

cout<<"|班级:

BM计算机091|"<

:

endl;

std:

:

cout<<"|完成日期:

2011-12-30|"<

:

endl;

std:

:

cout<<"*-----------------------*"<

:

endl;

std:

:

cout<

:

endl<<"按回车键继续";

getchar();

}

/*----------------------------程序提示信息结束------------------------------*/

/*----------------------------生产一个产品开始------------------------------*/

//生产一个产品,输出其ID号

voidProduce()

{

std:

:

cout<

:

endl;

std:

:

cerr<<"生产一个产品:

"<<++ProductID;

std:

:

cout<

:

endl;

}

/*----------------------------生产一个产品结束------------------------------*/

/*----------------------把新生产的产品放入缓冲区开------------------------*/

//把新生产的产品放入缓冲区

voidAppend()

{

std:

:

cerr<<"把生产的产品送入缓冲区";

g_buffer[in]=ProductID;

in=(in+1)%SIZE_OF_BUFFER;

std:

:

cerr<

:

endl;

std:

:

cout<<"缓冲区产品生产者/消费者"<

:

endl;

//新产品放入缓冲区后,输出缓冲区当前的状态

for(inti=0;i

{

//输出缓冲区下标

if(i<10)

std:

:

cout<

else

std:

:

cout<

if(i==in)

{

if(g_buffer[i]<10)

std:

:

cout<<"";

else

std:

:

cout<<"";

std:

:

cout<<"<--生产者";//输出生产者的指针位置

}

if(i==out)

{

if(g_buffer[i]<10)

std:

:

cout<<"";

else

std:

:

cout<<"";

std:

:

cout<<"<--消费者";//输出消费者的指针位置

}

std:

:

cout<

:

endl;

}

}

/*----------------------把新生产的产品放入缓冲区结------------------------*/

/*----------------------------消费一个产品开始------------------------------*/

voidConsume()//消费一个产品

{

std:

:

cout<

:

endl;

std:

:

cerr<<"消费一个产品:

"<

std:

:

cout<

:

endl;

}

/*----------------------------消费一个产品结束------------------------------*/

/*-----------------------从缓冲区中取出一个产品开始-------------------------*/

//从缓冲区中取出一个产品

voidTake()

{

std:

:

cout<

:

endl;

std:

:

cerr<<"从缓冲区取出一个产品";

ConsumeID=g_buffer[out];

out=(out+1)%SIZE_OF_BUFFER;

std:

:

cerr<

:

endl;

std:

:

cout<

:

endl;

std:

:

cout<<"缓冲区产品生产者/消费者"<

:

endl;

//取出一个产品后,输出缓冲区当前的状态

for(inti=0;i

{

//输出缓冲区下标

if(i<10)

std:

:

cout<

else

std:

:

cout<

if(i==in)

{

if(g_buffer[i]<10)

std:

:

cout<<"";

else

std:

:

cout<<"";

std:

:

cout<<"<--生产者";//输出生产者的指针位置

}

if(i==out)

{

if(g_buffer[i]<10)

std:

:

cout<<"";

else

std:

:

cout<<"";

std:

:

cout<<"<--消费者";//输出消费者的指针位置

}

std:

:

cout<

:

endl;

}

}

/*-----------------------从缓冲区中取出一个产品结束-------------------------*/

/*-----------------------------生产者线程开始-------------------------------*/

//生产者线程

DWORDWINAPIProducer(LPVOIDlpPara)

{

while(g_continue)

{

//资源信号量的P操作

WaitForSingleObject(g_hFullSemaphore,INFINITE);

//互斥信号量的P操作

WaitForSingleObject(g_hMutex,INFINITE);

//生产一个产品

Produce();

//把新生产的产品放入缓冲区

Append();

Sleep(2000);

//互斥信号量的V操作

ReleaseMutex(g_hMutex);

//资源信号量的V操作

ReleaseSemaphore(g_hEmptySemaphore,1,NULL);

}

return0;

}

/*-----------------------------生产者线程结束-------------------------------*/

/*-----------------------------消费者线程开始-------------------------------*/

//消费者线程

DWORDWINAPIConsumer(LPVOIDlpPara)

{

while(g_continue)

{

//资源信号量的P操作

WaitForSingleObject(g_hEmptySemaphore,INFINITE);

//互斥信号量的P操作

WaitForSingleObject(g_hMutex,INFINITE);

//从缓冲区中取出一个产品

Take();

//消费一个产品

Consume();

Sleep(2000);

//互斥信号量的V操作

ReleaseMutex(g_hMutex);

//资源信号量的V操作

ReleaseSemaphore(g_hFullSemaphore,1,NULL);

}

return0;

}

/*-----------------------------消费者线程结束-------------------------------*/

/*---------------------------创建生产者线程开始-----------------------------*/

voidcreatePT()//创建生产者线程

{

for(inti=0;i

{

hThreads[i]=CreateThread(NULL,0,Producer,NULL,0,&producerID[i]);

if(hThreads[i]==NULL)

g_continue=0;

}

}

/*---------------------------创建生产者线程结束-----------------------------*/

/*---------------------------创建消费者线程开始-----------------------------*/

voidcreateCT()//创建消费者线程

{

for(intj=0;j

{

hThreads[PRODUCERS_COUNT+j]=CreateThread(NULL,0,Consumer,NULL,0,&consumerID[j]);

if(hThreads[j]==NULL)

g_continue=0;

}

}

/*---------------------------创建消费者线程结束-----------------------------*/

/*-------------------------------主函数开始---------------------------------*/

intmain()

{

//显示程序提示信息

info();

//创建互斥信号量

g_hMutex=CreateMutex(NULL,FALSE,NULL);

//创建资源信号量

g_hFullSemaphore=CreateSemaphore(NULL,SIZE_OF_BUFFER-1,SIZE_OF_BUFFER-1,NULL);

g_hEmptySemaphore=CreateSemaphore(NULL,0,SIZE_OF_BUFFER-1,NULL);

//创建生产者线程

createPT();

//创建消费者线程

createCT();

//不按回车键的话程序会一直运行下去

while(g_continue)

//按回车键终止程序

if(getchar())

g_continue=0;

}

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 自然科学 > 物理

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2