生产者消费者问题代码Word格式.docx
- 文档编号:21813848
- 上传时间:2023-02-01
- 格式:DOCX
- 页数:16
- 大小:21.12KB
生产者消费者问题代码Word格式.docx
《生产者消费者问题代码Word格式.docx》由会员分享,可在线阅读,更多相关《生产者消费者问题代码Word格式.docx(16页珍藏版)》请在冰豆网上搜索。
//一个信号量;
HANDLEh_mutex;
//一个互斥量;
DWORDn_Thread=0;
//实际的线程的数目;
//dword:
doubleword,两个字节,三十二位
DWORDn_Buffer_or_Critical;
//实际的缓冲区或者临界区的数目;
HANDLEh_Semaphore[MAX_THREAD_NUM];
//生产者允许消费者开始消费的信号量;
//生产消费及辅助函数的声明
voidProduce(void*p);
voidConsume(void*p);
boolIfInOtherRequest(int);
intFindProducePositon();
intFindBufferPosition(int);
intmain(void)
//声明所需变量;
DWORDwait_for_all;
ifstreaminFile;
//ifstream:
读操作文件类,ofstream:
写操作文件类,fstream:
读写操作文件类
//初始化缓冲区;
for(inti=0;
i<
MAX_BUFFER_NUM;
i++)
Buffer_Critical[i]=-1;
//初始化每个线程的请求队列;
for(intj=0;
j<
MAX_THREAD_NUM;
j++){
for(intk=0;
k<
k++)
Thread_Info[j].thread_request[k]=-1;
//-1代表不请求
Thread_Info[j].n_request=0;
}
//初始化临界区;
for(i=0;
i++)
InitializeCriticalSection(&
PC_Critical[i]);
/*VOIDInitializeCriticalSection(LPCRITICAL_SECTIONlpCriticalSection)
初始化一个临界资源对象
lpCriticalSection临界资源对象指针*/
//打开输入文件,按照规定的格式提取线程等信息;
inFile.open("
test.txt"
);
/*voidopen(constchar*filename,openmodemode)
通过一个流对象打开一个文件
filename为文件名,mode为控制模式
其余有voidclose()*/
//从文件中获得实际的缓冲区的数目;
inFile>
>
n_Buffer_or_Critical;
//从输入流读取一个字符
inFile.get();
//从输入流读取一个字符,并将它转成int值送返,但不赋值给变量
printf("
输入文件是:
\n"
//回显获得的缓冲区的数目信息;
\n缓冲区数%d\n"
(int)n_Buffer_or_Critical);
//提取每个线程的信息到相应数据结构中;
while(inFile)
{
inFile>
Thread_Info[n_Thread].serial;
Thread_Info[n_Thread].entity;
Thread_Info[n_Thread].delay;
charc;
inFile.get(c);
while(c!
='
\n'
&
!
inFile.eof())//eof当到达文件末尾时返回true
{
inFile>
Thread_Info[n_Thread].thread_request[Thread_Info[n_Thread].n_request++];
inFile.get(c);
}
n_Thread++;
}
//回显获得的线程信息,便于确认正确性;
for(j=0;
(int)n_Thread;
intTemp_serial=Thread_Info[j].serial;
charTemp_entity=Thread_Info[j].entity;
doubleTemp_delay=Thread_Info[j].delay;
printf("
\n线程%2d\t类型:
%c\t延迟:
%f\t"
Temp_serial,Temp_entity,Temp_delay);
intTemp_request=Thread_Info[j].n_request;
if(Temp_request)
printf("
消费请求队列:
"
Temp_request;
\t%d"
Thread_Info[j].thread_request[k]);
cout<
<
endl;
\n\n"
//创建在模拟过程中几个必要的信号量
empty_semaphore=CreateSemaphore(NULL,n_Buffer_or_Critical,n_Buffer_or_Critical,"
semaphore_for_empty"
h_mutex=CreateMutex(NULL,FALSE,"
mutex_for_update"
/*HANDLECreateSemaphore(
LPSECURITY_ATTRIBUTESlpSemaphoreAttributes,
LONGlInitialCount,
LONGlMaximumCount,
LPCTSTRlpName
);
lpSemaphoreAttributesSECURITY_ATTRIBUTES,指定一个SECURITY_ATTRIBUTES结构,或传递零值(将参数声明为ByValAsLong,
并传递零值)——表示采用不允许继承的默认描述符。
该参数定义了信号量的安全特性
lInitialCountLong,设置信号量的初始计数。
可设置零到lMaximumCount之间的一个值
lMaximumCountLong,设置信号量的最大计数
pNameString,指定信号量对象的名称。
成功时返回信号量句柄*/
/*HANDLECreateMutex(
LPSECURITY_ATTRIBUTESlpMutexAttributes,//指向安全属性的指针
BOOLbInitialOwner,//初始化互斥对象的所有者
LPCTSTRlpName//指向互斥对象名的指针
lpMutexAttributesSECURITY_ATTRIBUTES,指定一个SECURITY_ATTRIBUTES结构,或传递零值(将参数声明为ByValAsLong,并传
递零值),表示使用不允许继承的默认描述符
bInitialOwnerLong,如创建进程希望立即拥有互斥体,则设为TRUE。
一个互斥体同时只能由一个线程拥有
lpNameString,指定互斥体对象的名字。
成功时返回互斥体对象名称*/
//下面这个循环用线程的ID号来为相应生产线程的产品读写时所使用的同步信号量命名;
(int)n_Thread;
j++){
std:
:
stringlp="
semaphore_for_produce_"
;
inttemp=j;
while(temp){
charc=(char)(temp%10);
lp+=c;
temp/=10;
h_Semaphore[j+1]=CreateSemaphore(NULL,0,n_Thread,lp.c_str());
//创建生产者和消费者线程;
(int)n_Thread;
i++){
if(Thread_Info[i].entity=='
P'
)
h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(Produce),
&
(Thread_Info[i]),0,NULL);
/*HANDLECreateThread(
LPSECURITY_ATTRIBUTESlpThreadAttributes,//SD
SIZE_TdwStackSize,//initialstacksize
LPTHREAD_START_ROUTINElpStartAddress,//threadfunction
LPVOIDlpParameter,//threadargument
DWORDdwCreationFlags,//creationoption
LPDWORDlpThreadId//threadidentifier
);
lpThreadAttributes:
指向SECURITY_ATTRIBUTES型态的结构的指针。
dwStackSize,设置初始栈的大小,以字节为单位,如果为0,那么默认将使用与调用该函数的线程相同的栈空间大小。
任何情况下,
Windows根据需要动态延长堆栈的大小。
lpStartAddress,指向线程函数的指针,形式:
@函数名,函数名称没有限制
lpParameter:
向线程函数传递的参数,是一个指向结构的指针,不需传递参数时,为NULL。
dwCreationFlags:
线程标志
lpThreadId:
保存新线程的id。
函数成功,返回线程句柄;
函数失败返回false。
*/
else
h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(Consume),
//主程序等待各个线程的动作结束;
wait_for_all=WaitForMultipleObjects(n_Thread,h_Thread,TRUE,-1);
\n\n所有生产者和消费者均已完成任务.\n"
Pressanykeytoquit!
_getch();
return0;
}
//以下函数由windows隐式调用
//确认是否还有对同一产品的消费请求未执行;
boolIfInOtherRequest(intreq)
n_Thread;
for(intj=0;
Thread_Info[i].n_request;
j++)
if(Thread_Info[i].thread_request[j]==req)
returnTRUE;
returnFALSE;
//找出当前可以进行产品生产的空缓冲区位置;
intFindProducePosition()
intEmptyPosition;
for(inti=0;
n_Buffer_or_Critical;
if(Buffer_Critical[i]==-1){
EmptyPosition=i;
//用下面这个特殊值表示本缓冲区正处于被写状态;
Buffer_Critical[i]=-2;
break;
returnEmptyPosition;
//找出当前所需生产者生产的产品的位置;
intFindBufferPosition(intProPos)
intTempPos;
for(inti=0;
if(Buffer_Critical[i]==ProPos){
TempPos=i;
returnTempPos;
//生产者进程
voidProduce(void*p)
//局部变量声明;
DWORDwait_for_semaphore,wait_for_mutex,m_delay;
intm_serial;
//获得本线程的信息;
m_serial=((ThreadInfo*)(p))->
serial;
m_delay=(DWORD)(((ThreadInfo*)(p))->
delay*INTE_PER_SEC);
Sleep(m_delay);
//延迟
//开始请求生产
生产者%2d请求生产.\n"
m_serial);
//确认有空缓冲区可供生产,同时将空位置数empty减1;
用于生产者和消费者的同步;
wait_for_semaphore=WaitForSingleObject(empty_semaphore,-1);
/*DWORDWaitForSingleObject(
HANDLEhHandle,
DWORDdwMilliseconds
)
hHandle[in]对象句柄。
dwMilliseconds[in]定时时间间隔,单位为milliseconds(毫秒)。
执行成功,返回值指示出引发函数返回的事件。
//互斥访问下一个可用于生产的空临界区,实现写写互斥;
wait_for_mutex=WaitForSingleObject(h_mutex,-1);
intProducePos=FindProducePosition();
ReleaseMutex(h_mutex);
/*BOOLWIANPIReleaseMutex(
HANDLEhMutex
hMutex:
HANDLE,制定一个互斥体的句柄。
BOOL,TRUE表示成功,FALSE表示失败。
//生产者在获得自己的空位置并做上标记后,以下的写操作在生产者之间可以并发;
//核心生产步骤中,程序将生产者的ID作为产品编号放入,方便消费者识别;
生产者%2d开始在缓冲区%2d生产.\n"
m_serial,ProducePos);
Buffer_Critical[ProducePos]=m_serial;
生产者%2d结束生产.\n"
\t缓冲区[%2d]:
%3d\n"
ProducePos,Buffer_Critical[ProducePos]);
//使生产者写的缓冲区可以被多个消费者使用,实现读写同步;
ReleaseSemaphore(h_Semaphore[m_serial],n_Thread,NULL);
//消费者进程
voidConsume(void*p)
DWORDwait_for_semaphore,m_delay;
intm_serial,m_requestNum;
//消费者的序列号和请求的数目;
intm_thread_request[MAX_THREAD_NUM];
//本消费线程的请求队列;
//提取本线程的信息到本地;
m_requestNum=((ThreadInfo*)(p))->
n_request;
for(inti=0;
m_requestNum;
m_thread_request[i]=((ThreadInfo*)(p))->
thread_request[i];
//循环进行所需产品的消费
i++){
//请求消费下一个产品
消费者%2d请求消费产品%2d\n"
m_serial,m_thread_request[i]);
//如果对应生产者没有生产,则等待;
如果生产了,允许的消费者数目-1;
实现了读写同步;
wait_for_semaphore=WaitForSingleObject(h_Semaphore[m_thread_request[i]],-1);
//查询所需产品放到缓冲区的号
intBufferPos=FindBufferPosition(m_thread_request[i]);
//开始进行具体缓冲区的消费处理,读和读在该缓冲区上仍然是互斥的;
//进入临界区后执行消费动作;
并在完成此次请求后,通知另外的消费者本处请求已
//经满足;
同时如果对应的产品使用完毕,就做相应处理;
并给出相应动作的界面提
//示;
该相应处理指将相应缓冲区清空,并增加代表空缓冲区的信号量;
EnterCriticalSection(&
PC_Critical[BufferPos]);
/*引入互斥变量时,使用EnterCriticalSection进入互斥状态,此时其他线程不得访问临界区;
使用LeaveCriticalSection后解除
互斥状态。
消费者%2d开始消费产品%2d\n"
((ThreadInfo*)(p))->
thread_request[i]=-1;
if(!
IfInOtherRequest(m_thread_request[i])){
Buffer_Critical[BufferPos]=-1;
//标记缓冲区为空;
消费者%2d结束消费产品%2d:
\n"
%s\n"
BufferPos,"
空"
ReleaseSemaphore(empty_semaphore,1,NULL);
/*BOOLReleaseSemaphore(
HANDLEhSemaphore,
LONGlReleaseCount,
LPLONGlpPreviousCount
)
hSemaphore:
所要操作的信号量对象的句柄,这个句柄是CreateSemaphore或者OpenSemaphore函数的返回值。
lReleaseCount:
这个信号量对象在当前基础上所要增加的值,这个值必须大于0。
lpPreviousCount:
指向返回信号量上次值的变量的指针,如果不需要信号量上次的值,那么这个参数可以设置为NULL。
成功返回TRUE,如果失败返回FALSE。
*/
}
else{
消费者%2d结束消费产品%2d\n"
//离开临界区
LeaveCriticalSection(&
test.txt
5
1P3
2P4
3C41
4P2
5C312
6C2124
#include<
iostream>
constunsignedshortSIZE_OF_BUFFER=10;
//缓冲区长度
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=CreateSema
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 生产者 消费者 问题 代码
![提示](https://static.bdocx.com/images/bang_tan.gif)