生产者与消费者问题的模拟实现
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
操作系统
课程设计报告
专业计算机科学与技术学生姓名郑伟
班级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操作,释放资源。
如果缓冲区中已经没有可用资源,就把申请资源的进程添加到等待队列的队尾。
如果有一个资源被释放,在等待队列中的第一个进程被唤醒并取得这个资源的使用权。
数据结构及信号量定义的说明;
#define Size 20
struct huan{
int isHave; //标记缓冲区是否有内容,有内
容时,消费者才可以使用,
//没内容时,生产者才可以往缓冲区内写东西 //0表示没有内容,1表示有内容
int jud; //标志缓冲区是否在被使用中,0
代表未被使用,1表示使用中
int context; //缓冲的内容
};
描叙生产者或消费者:
struct person{
int end; //记录是否完成任务,0表示完成,1
表示未完成任务
char * name; /*线程名*/
pthread_t thread; /*线程句柄*/
};
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 <windows.h>
#include <iostream>
const unsigned short SIZE_OF_BUFFER = 20;//有界缓冲区长度
int g_buffer[SIZE_OF_BUFFER];//开辟缓冲区,用数组表示,可以看成是一个循环队列unsigned short ProductID = 0;//新生产出来的产品的产品号
unsigned short ConsumeID = 0;//被消耗的产品的产品号
unsigned short in = 0;//产品进缓冲区时的缓冲区下标,用于记录生产者的指针位置unsigned short out = 0;//产品出缓冲区时的缓冲区下标,用于记录消费者的指针位置
bool g_continue = 1;//控制程序运行:1表示继续运行,0表示停止运行
HANDLE g_hMutex;//线程间的互斥信号量
HANDLE g_hFullSemaphore;//资源信号量:缓冲区满
HANDLE g_hEmptySemaphore;//资源信号量:缓冲区空
DWORD WINAPI Producer(LPVOID);//生产者线程
DWORD WINAPI Consumer(LPVOID);//消费者线程
const unsigned short PRODUCERS_COUNT=4;//生产者的个数
const unsigned short CONSUMERS_COUNT=3;//消费者的个数
const unsigned short THREADS_COUNT=PRODUCERS_COUNT+CONSUMERS_COUNT;//总线程数
HANDLE hThreads[PRODUCERS_COUNT];//各线程的handle
DWORD producerID[CONSUMERS_COUNT];//生产者线程的标识符
DWORD consumerID[THREADS_COUNT];//消费者线程的标识符
/*----------------------------程序提示信息开始------------------------------*/
void info()//程序提示信息
{
std::cout<<"* - - - - - - - - - - - - - - - - - - - - - - - *"<<std::endl;
std::cout<<"| 题目:生产者消费者问题|"<<std::endl;
std::cout<<"| 指导老师:李先锋|"<<std::endl;
std::cout<<"| 作者:郑伟|"<<std::endl;
std::cout<<"| 代码行数:200+ |"<<std::endl;
std::cout<<"| 班级:BM计算机091 |"<<std::endl;
std::cout<<"| 完成日期:2011-12-30 |"<<std::endl;
std::cout<<"* - - - - - - - - - - - - - - - - - - - - - - - *"<<std::endl;
std::cout<<std::endl<<"按回车键继续";
getchar();
}
/*----------------------------程序提示信息结束------------------------------*/
/*----------------------------生产一个产品开始------------------------------*/ //生产一个产品,输出其ID号
void Produce()
{
std::cout<<std::endl;
std::cerr<<"生产一个产品: "<<++ProductID;
std::cout<<std::endl;
}
/*----------------------------生产一个产品结束------------------------------*/
/*----------------------把新生产的产品放入缓冲区开------------------------*/ //把新生产的产品放入缓冲区
void Append()
{
std::cerr<<"把生产的产品送入缓冲区";
g_buffer[in]=ProductID;
in=(in+1)%SIZE_OF_BUFFER;
std::cerr<<std::endl;
std::cout<<"缓冲区产品生产者/消费者"<<std::endl;
//新产品放入缓冲区后,输出缓冲区当前的状态
for(int i=0;i<SIZE_OF_BUFFER;++i)
{
//输出缓冲区下标
if (i<10)
std::cout<<i<<" "<<g_buffer[i];
else
std::cout<<i<<" "<<g_buffer[i];
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<<std::endl;
}
}
/*----------------------把新生产的产品放入缓冲区结------------------------*/ /*----------------------------消费一个产品开始------------------------------*/ void Consume()//消费一个产品
{
std::cout<<std::endl;
std::cerr<<"消费一个产品: "<<ConsumeID;
std::cout<<std::endl;
}
/*----------------------------消费一个产品结束------------------------------*/
/*-----------------------从缓冲区中取出一个产品开始-------------------------*/ //从缓冲区中取出一个产品
void Take()
{
std::cout<<std::endl;
std::cerr<<"从缓冲区取出一个产品";
ConsumeID=g_buffer[out];
out=(out+1)%SIZE_OF_BUFFER;
std::cerr<<std::endl;
std::cout<<std::endl;
std::cout<<"缓冲区产品生产者/消费者"<<std::endl;
//取出一个产品后,输出缓冲区当前的状态
for(int i=0;i<SIZE_OF_BUFFER;++i)
{
//输出缓冲区下标
if(i<10)
std::cout<<i<<" "<<g_buffer[i];
else
std::cout<<i<<" "<<g_buffer[i];
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<<std::endl;
}
}
/*-----------------------从缓冲区中取出一个产品结束-------------------------*/ /*-----------------------------生产者线程开始-------------------------------*/
//生产者线程
DWORD WINAPI Producer(LPVOID lpPara)
{
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);
}
return 0;
}
/*-----------------------------生产者线程结束-------------------------------*/
/*-----------------------------消费者线程开始-------------------------------*/ //消费者线程
DWORD WINAPI Consumer(LPVOID lpPara)
{
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);
}
return 0;
}
/*-----------------------------消费者线程结束-------------------------------*/
/*---------------------------创建生产者线程开始-----------------------------*/
void createPT()//创建生产者线程
{
for(int i=0;i<PRODUCERS_COUNT;++i)
{
hThreads[i]=CreateThread(NULL,0,Producer,NULL,0,&producerID[i]);
if(hThreads[i]==NULL)
g_continue=0;
}
}
/*---------------------------创建生产者线程结束-----------------------------*/
/*---------------------------创建消费者线程开始-----------------------------*/
void createCT()//创建消费者线程
{
for (int j=0;j<CONSUMERS_COUNT;++j)
{
hThreads[PRODUCERS_COUNT+j]=CreateThread(NULL,0,Consumer,NULL,0,&consume rID[j]);
if (hThreads[j]==NULL)
g_continue=0;
}
}
/*---------------------------创建消费者线程结束-----------------------------*/
/*-------------------------------主函数开始---------------------------------*/
int main()
{
//显示程序提示信息
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;
}。