实验4生产者消费者问题报告.docx
《实验4生产者消费者问题报告.docx》由会员分享,可在线阅读,更多相关《实验4生产者消费者问题报告.docx(13页珍藏版)》请在冰豆网上搜索。
![实验4生产者消费者问题报告.docx](https://file1.bdocx.com/fileroot1/2023-5/29/fdca06a9-4eda-4a9e-90c9-2967504aba02/fdca06a9-4eda-4a9e-90c9-2967504aba021.gif)
实验4生产者消费者问题报告
南京信息工程大学实验(实习)报告
实验(实习)名称生产者-消费者问题的模拟实现实验(实习)日期11.29得分指导教师陈遥
系计算机专业科学与技术年级2012班次1姓名王林学号20122308025
一、实验目的
本实验的目的是通过编写和调试一个解决生产者–消费者问题的简单模拟程序,进一步深入理解课堂教学中讲授的进程同步问题,以及用于解决同步问题的信号量机制的基本思想,即通过研究进程同步和信号量机制实现生产者消费者问题的并发控制,以便阶段性地巩固学习成果。
二、实验内容
(1)概述
说明:
有界缓冲区内设有20个存储单元,放入/取出的数据项设定为1-20这20个整型数。
编制程序模拟解决生产者-消费者同步问题。
具体设计要求:
(1)每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区的全部内容,当前指针位置和生产者/消费线程的标识符。
(2)生产者和消费者各有两个以上。
(3)多个生产者或多个消费者之间须有共享对缓冲区进行操作的函数代码。
(2)设计原理
通过一个有界缓冲区把生产者和消费者联系起来。
假定生产者和消费者的优先级是相同的,只要缓冲区未满,生产者就可以生产产品并将产品送入缓冲区。
类似地,只要缓冲区未空,消费者就可以从缓冲区中取走产品。
应该禁止生产者向满的缓冲区送入产品,同时也应该禁止消费者从空的缓冲区中取出产品,这一机制由生产者线程和消费者线程之间的互斥关系来实现。
与计算打印两进程同步关系相同,生产者和消费者两进程Producer和Consumer之间应满足下列两个同步条件:
1只有在缓冲池中至少有一个缓冲区已存入消息后,消费者才能从中提取信息,否则消费者必须等待。
2只有缓冲池中至少有一个缓冲区是空时,生产者才能把消息放入缓冲区,否则生产者必须等待。
为了满足第一个同步条件,设置一个同步信号量full,它代表的资源是缓冲区满,它的初始值为0,它的值为n时整个缓冲池满。
这个资源是消费者进程Consumer所有,Consumer进程可以申请该资源,对它施加P操作,而Consumer进程的合作进程生产者进程Producer对它施加V操作。
同样为了满足第二个同步条件,设置另一个同步信号量empty,它代表的资源是缓冲空区,它的初始值为n,表示缓冲池中所有缓冲区空。
信号量full表示可用缓冲区数量,信号量empty表示缓冲区数量,设置整型变量:
存入指针in和取出指针out。
为解决生产者/消费者问题,应该设置两个资源信号量,其中一个表示空缓冲区的数目,用g_hFullSemaphore表示,其初始值为有界缓冲区的大小SIZE_OF_BUFFER;另一个表示缓冲区中产品的数目,用g_hEmptySemaphore表示,其初始值为0。
另外,由于有界缓冲区是一个临界资源,必须互斥使用,所以还需要在设置一个互斥信号量g_hMutex,初始值为1.
P原语的主要动作是:
1sem(信号量)减1;
2若sem减一后仍大于或等于零,则进程继续执行;
3若sem减一后小于零,则该进程被阻塞后入与该信号相对应的队列中,然后转进程调度。
V原语的操作主要动作是:
1sem加1;
2若相加结果大于零,进程继续执行;
③若相加结果小于或等于零,则从该信号的等待队列中唤醒一等待进程然后再返回原进程继续执行或转进程调度。
采用的同步方法:
1)利用函数CreateMutex(NULL,FALSE,NULL)创建互斥信号量g_hMutex,表示缓冲区当前的状态,若为true时,则表示缓冲区正被别的进程使用。
三个参数表示的意义分别为:
指向安全属性的指针,初始化互斥对象的所有者,指向互斥对象名的指针。
2)利用函数CreateSemaphore(NULL,SIZE_OF_BUFFER-1,SIZE_OF_BUFFER-1,
NULL)创建缓冲区空的信号量g_hFullSemaphore,值为true时表示缓冲区已满。
四个参数分别为:
表示是否允许继承、设置信号机的初始计数、设置信号机的最大计数、指定信号机对象的名称(-1是因为计数从开始)。
3)利用函数CreateSemaphore(NULL,0,SIZE_OF_BUFFER-1,NULL)创建缓冲区满的信号量g_hEmptySemaphore,该值为true时表示缓冲区为空。
5、数据定义及其详细解释
constunsignedshortSIZE_OF_BUFFER=20;//缓冲区长度
unsignedshortProductID=0;//产品号
unsignedshortConsumeID=0;//将被消耗的产品号
unsignedshortin=0;//产品进缓冲区时的缓冲区下标
unsignedshortout=0;//产品出缓冲区时的缓冲区下标
intg_buffer[SIZE_OF_BUFFER];//缓冲区是个循环队列
boolg_continue=true;//使程序跳出循环,控制程序结束
HANDLEg_hMutex;//用于线程间的互斥
HANDLEg_hFullSemaphore;//当缓冲区满时迫使生产者等待
HANDLEg_hEmptySemaphore;//当缓冲区空时迫使消费者等待
DWORDWINAPIProducer(LPVOID);//生产者线程
DWORDWINAPIConsumer(LPVOID);//消费者线程
(3)详细设计及编码
流程图
生产者
:
消费者:
运行代码及结果:
#include
#include
constunsignedshortSIZE_OF_BUFFER=20;//缓冲区长度
unsignedshortProductID=0;//产品号
unsignedshortConsumeID=0;//将被消耗的产品号
unsignedshortin=0;//产品进缓冲区时的缓冲区下标
unsignedshortout=0;//产品出缓冲区时的缓冲区下标
intg_buffer[SIZE_OF_BUFFER];//缓冲区是个循环队列
boolg_continue=true;//控制程序结束
HANDLEg_hMutex;//用于线程间的互斥
HANDLEg_hFullSemaphore;//当缓冲区满时迫使生产者等待
HANDLEg_hEmptySemaphore;//当缓冲区空时迫使消费者等待
DWORDWINAPIProducer(LPVOID);//生产者线程
DWORDWINAPIConsumer(LPVOID);//消费者线程
intmain()
{
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);
constunsignedshortPRODUCERS_COUNT=2;//生产者的个数
constunsignedshortCONSUMERS_COUNT=1;//消费者的个数
constunsignedshortTHREADS_COUNT=PRODUCERS_COUNT+CONSUMERS_COUNT;//总的进程数
HANDLEhThreads[THREADS_COUNT];//各线程的handle
DWORDproducerID[PRODUCERS_COUNT];//生产者线程的标识符
DWORDconsumerID[CONSUMERS_COUNT];//消费者线程的标识符
//加注释,说明该For循环的作用
for(inti=0;ihThreads[i]=CreateThread(NULL,0,Producer,NULL,0,&producerID[i]);
//加注释,说明上面函数的功能,各参数的含义
if(hThreads[i]==NULL)return-1;
}
//加注释,说明该For循环的作用
for(i=0;ihThreads[PRODUCERS_COUNT+i]=CreateThread(NULL,0,Consumer,NULL,0,&consumerID[i]);
if(hThreads[i]==NULL)return-1;
}
while(g_continue){
if(getchar()){//按回车后终止程序运行
g_continue=false;
}
}
return0;
}
//加注释,说明下面函数的功能
voidProduce()
{
std:
:
cerr<<"Producing"<<++ProductID<<"...";
std:
:
cerr<<"Succeed"<:
endl;
}
//加注释,说明下面函数的功能
voidAppend()
{
std:
:
cerr<<"Appendingaproduct...";
g_buffer[in]=ProductID;
in=(in+1)%SIZE_OF_BUFFER;
std:
:
cerr<<"Succeed"<:
endl;
//输出缓冲区当前的状态
for(inti=0;istd:
:
cout<
"<if(i==in)std:
:
cout<<"<--生产";
if(i==out)std:
:
cout<<"<--消费";
std:
:
cout<:
endl;
}
}
//加注释,说明下面函数的功能
voidTake()
{
std:
:
cerr<<"Takingaproduct...";
ConsumeID=g_buffer[out];
out=(out+1)%SIZE_OF_BUFFER;
std:
:
cerr<<"Succeed"<:
endl;
//输出缓冲区当前的状态
for(inti=0;istd:
:
cout<
"<if(i==in)std:
:
cout<<"<--生产";
if(i==out)std:
:
cout<<"<--消费";
std:
:
cout<:
endl;
}
}
//加注释,说明下面函数的功能
voidConsume()
{
std:
:
cerr<<"Consuming"<std:
:
cerr<<"Succeed"<:
endl;
}
//加注释,说明下面函数的功能
DWORDWINAPIProducer(LPVOIDlpPara)
{
while(g_continue){
WaitForSingleObject(g_hFullSemaphore,INFINITE);
//加注释,说明上面函数的功能,各参数的含义
WaitForSingleObject(g_hMutex,INFINITE);
Produce();
Append();
Sleep(1500);
ReleaseMutex(g_hMutex);
//加注释,说明上面函数的功能,各参数的含义
ReleaseSemaphore(g_hEmptySemaphore,1,NULL);
//加注释,说明上面函数的功能,各参数的含义
}
return0;
}
//加注释,说明下面函数的功能
DWORDWINAPIConsumer(LPVOIDlpPara)
{
while(g_continue){
WaitForSingleObject(g_hEmptySemaphore,INFINITE);
WaitForSingleObject(g_hMutex,INFINITE);
Take();
Consume();
Sleep(1500);
ReleaseMutex(g_hMutex);
ReleaseSemaphore(g_hFullSemaphore,1,NULL);
}
return0;
}
输入输出数据说明和分析:
该程序设置的缓冲区数据长度为20,生产者个数为3,消费者个数为1,程序启动后,生产者先进行生产,当3个生产者全部生产完之后,消费者开始从缓冲区中取出产品,当消费者取出一个后,生产者开始继续生产,当生产完3个之后,消费者开始从缓冲池中取产品,依次循环。
三、小结
本次课程设计主要是对操作系统中线程,进程同步互斥等知识的应用,生产者—消费者问题是很著名的同步问题,的确是既简单又复杂。