实验二生产者和消费者.docx
《实验二生产者和消费者.docx》由会员分享,可在线阅读,更多相关《实验二生产者和消费者.docx(11页珍藏版)》请在冰豆网上搜索。
实验二生产者和消费者
1.1实验目标
掌握操作系统对进程管理的同步和互斥问题,以经典同步问题“生产者和消费者”为例,运用所学C语言知识,编写该问题的模拟运行环境。
1.2实验环境
教案机房,C语言程序平台。
1.3实验内容及步骤
1.了解经典同步问题“生产者和消费者”
生产者与消费者可以通过一个环形缓冲池联系起来,环形缓冲池由几个大小相等的缓冲块组成,每个缓冲块容纳一个产品。
每个生产者可不断地每次往缓冲池中送一个生产产品,而每个消费者则可不断地每次从缓冲池中取出一个产品。
指针i和指针j分别指出当前的第一个空缓冲块和第一个满缓冲块。
b5E2RGbCAP
2.分析和理解
<1)既存在合作同步问题,也存在临界区互斥问题
合作同步:
当缓冲池全满时,表示供过于求,生产者必须等待,同时唤醒消费者;当缓冲池全空时,表示供不应求,消费者应等待,同时唤醒生产者。
p1EanqFDPw
互斥:
缓冲池显然是临界资源,所在生产者与消费都要使用它,而且都要改变它的状态。
<2)基于环形缓冲区的生产者与消费者关系形式描述:
公用信号量mutex:
初值为1,用于实现临界区互斥
生产者私用信号量empty:
初值为n,指示空缓冲块数目
消费者私用信号量full:
初值为0,指示满缓冲块数目
整型量i和j初值为0,i指示首空缓冲块序号,j指示首满缓冲块序号
<3)PV原语
varmutex,empty,full:
semaphore。
i,j:
integer。
buffer:
array[0...n-1]ofitem。
i:
=j:
=1。
Procedureproducer。
begin
whiletruedo
begin
produceaproduct。
P(empty>。
P(mutex>。
buffer(i>:
=product。
i:
=(i+1>modn。
V(mutex>。
V(full>。
end。
end。
Procedureconsumer。
begin
P(full>。
P(mutex>。
goods:
=buffer(j>。
j:
=(j+1>modn。
V(mutex>。
V(empty>。
consumeaproduct。
end。
end。
3.用C语言编程搭建“生产者和消费者”经典进程通信问题的环境。
要求程序运行时,按任意键停止,显示当前系统的各个参数的值。
提交实验报告,以及相关程序列表。
打包成附件上传。
DXDiTa9E3d
#include
#include
#include
#defineP(S>WaitForSingleObject(S,INFINITE>//定义Windows下的P操作RTCrpUDGiT
#defineV(S>ReleaseSemaphore(S,1,NULL>//定义Windows下的V操作5PCzVD7HxA
#definerate1000
#defineCONSUMER_NUM10/*消费者个数*/
#definePRODUCER_NUM10/*生产者个数*/
#defineBUFFER_NUM4/*缓冲区个数*/
typedefHANDLESemaphore。
//信号量的Windows原型
char*thing[10]={"物品1","物品2","物品3","物品4","物品5",
"物品6","物品7","物品8","物品9","物品10"}。
structBuffer
{
intproduct[BUFFER_NUM]。
//缓冲区
intstart,end。
//两个指针
}g_buf。
Semaphoreg_semBuffer,g_semProduct,g_mutex。
jLBHrnAILg
//消费者线程
DWORDWINAPIConsumer(LPVOIDpara>
{
inti=*(int*>para。
//i表示第i个消费者
intptr,j。
//待消费的内容的指针
Sleep(100>。
while(1>
{
P(g_semProduct>。
//有产品,先锁住缓冲区
P(g_mutex>。
//记录消费的物品
ptr=g_buf.start。
//再移动缓冲区指针
g_buf.start=(g_buf.start+1>%BUFFER_NUM。
V(g_mutex>。
//让其他消费者或生产者使用g_buf
printf("消费者%d:
消费了buf[%d]里的=%s\n",i,ptr,thing[g_buf.product[ptr]]>。
xHAQX74J0X
Sleep(rate*rand(>%10+110>。
//消费完毕,并释放一个缓冲
V(g_semBuffer>。
if(j++>30>break。
}
getchar(>。
return0。
}
//生产者线程
DWORDWINAPIProducer(LPVOIDpara>
{
inti=*(int*>para-CONSUMER_NUM。
intptr。
intdata。
//产品
Sleep(100>。
while(1>
{
Sleep(rate*rand(>%10+110>。
data=rand(>%10。
//等待存放空间
P(g_semBuffer>。
//有地方,先锁住缓冲区
P(g_mutex>。
//记录消费的物品
ptr=g_buf.end。
//再移动缓冲区指针
g_buf.end=(g_buf.end+1>%BUFFER_NUM。
//让其他消费者或生产者使用g_buf
V(g_mutex>。
printf("生产者%d:
在buf[%d]里放入了%s\n",i,ptr,thing[data]>。
LDAYtRyKfE
g_buf.product[ptr]=data。
Sleep(rate/2*rand(>%10+110>。
//放好了完毕,释放一个产品
V(g_semProduct>。
}
return0。
}
intmain(intargc,char*argv[]>
{//线程技术,前面为消费者线程,后面为生产者线程
HANDLEhThread[CONSUMER_NUM+PRODUCER_NUM]。
//线程计数
//srand(time(>>。
DWORDtid。
inti=0。
//初始化信号量
g_mutex=CreateSemaphore(NULL,BUFFER_NUM,BUFFER_NUM,"mutexOfConsumerAndProducer">。
Zzz6ZB2Ltk
g_semBuffer=CreateSemaphore(NULL,BUFFER_NUM,BUFFER_NUM,"BufferSemaphone">。
dvzfvkwMI1
g_semProduct=CreateSemaphore(NULL,0,BUFFER_NUM,"ProductSemaphone">。
rqyn14ZNXI
if(!
g_semBuffer||!
g_semProduct||!
g_mutex>
{
printf("CreateSemaphoneError!
\n">。
return-1。
}
inttotalThreads=CONSUMER_NUM+PRODUCER_NUM。
//开启消费者线程
for(i=0。
ii++>
{
hThread[i]=CreateThread(NULL,0,Consumer,&i,0,&tid>。
EmxvxOtOco
if(hThread[i]>WaitForSingleObject(hThread[i],10>。
}
//开启生产者线程
for(。
ii++>
{
hThread[i]=CreateThread(NULL,0,Producer,&i,0,&tid>。
SixE2yXPq5
if(hThread[i]>WaitForSingleObject(hThread[i],10>。
}
//生产者和消费者的执行
WaitForMultipleObjects(totalThreads,hThread,TRUE,INFINITE>。
6ewMyirQFL
return0。
}
1.4实验思考题
1.思考在“生产者和消费者”经典同步问题中,两个P操作是否可以互换位置,以及两个V操作是否可以互换位置。
kavU42VRUs
在生产者-消费者问题中,如果将两个P操作,即P(full>和P(mutex>互换位置,或者P(empty>和P(mutex>互换位置,都可能引起死锁。
考虑系统中缓冲区全满时,若以生产者进程先执行了P(mutex>操作并获得成功,当再执行P(empty>操作时,他将因失败而进入阻塞状态,它期待消费者执行V(empty>来唤醒自己。
在此之前,它不可能执行V(mutex>操作,从而使企图通过P(mutex>进入自己的临界区的其他生产者和所有消费者进程全部进入阻塞状态,从而引起系统死锁。
类似地,消费者进程若先执行P(mutex>,后执行P(full>,同样可能造成死锁。
y6v3ALoS89
V(full>和V和VM2ub6vSTnP
2.思考在“哲学家就餐”经典同步问题中,如何修改程序,可以保证不会发生死锁现象。
<1)至多只允许有四位哲学家同时去拿左边的筷子,最终能保证至少有一位哲学家能够进餐,并在用毕是能释放出他用过的两只筷子,从而使更多的哲学家能够进餐。
0YujCfmUCw
<2)仅当哲学家的左、右两只筷子均可使用时,才允许他拿起筷子进餐。
<3)规定奇数号哲学家先拿他左边的筷子,然后再去拿右边的筷子,而偶数号哲学家则相反。
按此规定,将是1、2号哲学家竞争1号筷子;3、4号哲学家竞争3号筷子。
即五位哲学家都先竞争奇数号筷子,获得后,再去竞争偶数号筷子,最后总会有一位哲学家能获得两只筷子而进餐。
eUts8ZQVRd
3.思考在“读者与写者”经典同步问题中,如何修改程序,变为“写者优先”的算法。
<写者优先算法)
Varrmutex,wmutex,mutex,s:
semaphore=1,1,1,1。
Writecount:
integer:
=0。
Reader:
begin
Repeat
Wait(s>。
Wait(rmutex>。
Ifreadcount=0thenwait(wmutex>。
Readcount:
readcount+1。
Signal(rmutex>。
Signal(s>。
Performreadoperation。
Wait(rmutex>。
Readcount:
=readcount:
=readcount-1。
Ifreadcount=0thensignal(wmutex>。
Signal(rmutex>。
Untilfalse。
End
Writer:
begin
Repeat
Wait(mutex>。
Ifwritecount=0thenwait(s>。
Writecount:
writecount+1。
Signal(mutex>。
Wait(wmutex>。
Performwriteoperatin。
Signal(wmutex>。
Wait(mutex>。
Writecount=0thensignal(s>。
Signal(mutex>。
Untilfalse。
end
4.分析以下进程运行环境中出现的同步和互斥现象,列出相应的变量和参数。
理发店理有一位理发师、一把理发椅和n把供等候理发的顾客坐的椅子。
如果没有顾客,理发师便在理发椅上睡觉。
一个顾客到来时,它必须叫醒理发师。
如果理发师正在理发时又有顾客来到,则如果有空椅子可坐,就坐下来等待,否则就离开。
sQsAEJkW5T
理发师是顾客争用资源,用信号量barbers表示,初值为0;除此之外,顾客还要争用n张椅子,信号量customers表示等候理发的顾客,初值为0;最后设置信号量mutex用于这两个活动对资源barbers/customers的互斥,初值为1.另外还需要使用一个变量waiter,用于记录等候的顾客的数量。
GMsIasNXkA
申明:
所有资料为本人收集整理,仅限个人学习使用,勿做商业用途。