操作系统实验报告实验一.docx
《操作系统实验报告实验一.docx》由会员分享,可在线阅读,更多相关《操作系统实验报告实验一.docx(18页珍藏版)》请在冰豆网上搜索。
操作系统实验报告实验一
操作系统实验报告实验一
部门:
xxx
时间:
xxx
整理范文,仅供参考,可下载自行编辑
计算机操作系统实验报告
一、实验一“生产者-消费者”问题
二、实验目的:
通过对“生产者-消费者”问题编程实现,了解线程创建、同步信号量、互斥信号量、临界区的创建和使用。
了解线程互斥和同步机制。
了解PV原语和信号量在线程互斥和同步机制中的运用。
三、实验内容
有界缓冲区内设有5个存储单位,放入/取出的数据项设定为1~5这5个整形数。
要求每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区的全部内容、当前生产者/消费者标识符b5E2RGbCAP
四、分析设计
实验陈述:
1、基础知识:
本实验用到几个API函数:
CreatThread,CreatMutex,CreatSemaphore,WaitForSingleObject,ReleaseSemaphore,ReleaseMutex,InitializeCriticalSection,EnterCriticalSection,LeaveCriticalSectionp1EanqFDPw
这些函数的作用:
CreatThread:
创建一个线程,该线程在调用进程的地址空间中执
CreatMutex:
产生一个命名的或者匿名的互斥量对象。
WaitForSingleObject<对应p操作)锁上互斥锁,ReleaseMutex<对应v操作)打开互斥锁。
DXDiTa9E3d
CreateSemaphore:
创建一个命名的或者匿名的信号对象。
信号量可以看作是在互斥量上的一个扩展。
RTCrpUDGiT
WaitForSingleObject:
使程序处于等待状态,直到信号量<或互斥量)hHandle出现或者超过规定的等待最长时间,信号量出现指信号量大于或等于1,互斥量出现指打开互斥锁。
在返回之前将信号量减1或者锁上互斥锁。
5PCzVD7HxA
ReleaseSemaphore:
将所指信号量加上指定大小的一个量,执行成功,则返回非0值。
ReleaseMutex:
用来打开互斥量,即将互斥量加1。
成功调用则返回0。
InitializeCriticalSection:
该函数初始化临界区对象。
EnterCriticalSection:
该函数用于等待指定临界区对象的所有权。
当调用线程被赋予所有权时,该函数返回。
jLBHrnAILg
LeaveCriticalSection:
该函数释放指定的临界区对象的所有权。
五、测试数据设计及测试结果分析
已知测试用例文件输入的文件时:
5
thread1P5.000000
thread2P4.000000
thread3P2.000000
thread4C6.00000056
thread5P7.000000
thread6P1.000000
thread7C3.000000132
生产者6发送生产请求信号.
生产者6开始在缓冲区0生产产品.
生产者6完成生产过程:
缓冲区【0】:
6
生成者3发送生产请求信号.
生产者3开始在缓冲区1生产产品.
生产者3完成生产过程:
缓冲区【1】:
3
消费者7请求消费1产品
消费者7请求消费1产品
生产者2发送生成者请求信号.
生产者2开始在缓冲区2生产产品
生产者2完成生产过程:
缓冲区【2】:
2
生产者1发送生产请求信号.
生产者1开始在缓冲区3生产产品.
生产者1完成生产过程:
缓冲区【3】:
1
消费者7开始消费1产品
消费者7成功消费1:
缓冲区【3】:
-1
消费者7请求消费3产品
消费者7开始消费3产品
消费者7成功消费3:
缓冲区【1】:
-1
消费者7请求消费2产品
消费者7开始消费2产品
消费者7成功消费2:
缓冲区【2】:
-1
消费者4请求消费5产品
生产者5发送生产请求信号.
生产者5开始在缓冲区1生产产品
生产者5完成生产过程
缓冲区【1】:
5
消费者4请求消费5产品
消费者4请求消费5产品
缓冲区【1】:
-1
消费者4请求消费6产品
消费者4开始消费6产品
消费者4成功消费6:
缓冲区【0】:
-1
六、流程图
实验程序的结构图<流程图);
七、程序运行结果
八、实验体会
通过这次实验了解到生产者-消费者问题是一个经典的进程同步问题,以及在其中使用信号量机制,生产者与消费者问题要求我们设计在同一个进程地址空间内执行的两个线程。
生产者线程生产物品,然后将物品放置在一个空缓冲区中提供消费者线程消费,而消费者线程从缓冲区中获得物品,然后释放缓冲区。
当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区,当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来。
xHAQX74J0X
这次生产者和消费者问题的实验,不但加深了我对操作系统中多线程机制的理解和认识,更让我认识到知识的掌握,仅靠学习理论知识是远远不够的,要与实际动手操作相结合才能更好的理解和分析问题。
LDAYtRyKfE
九、源程序文件
#include
#include
#include
#include
#include
//定义一些常量;
//本程序允许的最大临界区数;
#defineMAX_BUFFER_NUM10
//秒到毫秒的乘法因子;
#defineINTE_PER_SEC1000
//本程序允许的生产和消费线程的总数;
#defineMAX_THREAD_NUM64
//定义一个结构,记录在测试文件中指定的每一个线程的参数
structThreadInfo
{
intserial。
//线程序列号
charentity。
//是P还是C
doubledelay。
//线程延迟
intthread_request[MAX_THREAD_NUM]。
//线程请求队列
intn_request。
//请求个数
}。
//全局变量的定义
//临界区对象的声明,用于管理缓冲区的互斥访问;
CRITICAL_SECTIONPC_Critical[MAX_BUFFER_NUM]。
intBuffer_Critical[MAX_BUFFER_NUM]。
//缓冲区声明,用于存放产品;Zzz6ZB2Ltk
HANDLEh_Thread[MAX_THREAD_NUM]。
//用于存储每个线程句柄的数组;dvzfvkwMI1
ThreadInfoThread_Info[MAX_THREAD_NUM]。
//线程信息数组;
HANDLEempty_semaphore。
//一个信号量;
HANDLEh_mutex。
//一个互斥量;
DWORDn_Thread=0。
//实际的线程的数目;
DWORDn_Buffer_or_Critical。
//实际的缓冲区或者临界区的数目;rqyn14ZNXI
HANDLEh_Semaphore[MAX_THREAD_NUM]。
//生产者允许消费者开始消费的信号量;EmxvxOtOco
//生产消费及辅助函数的声明
voidProduce(void*p>。
voidConsume(void*p>。
boolIfInOtherRequest(int>。
intFindProducePositon(>。
intFindBufferPosition(int>。
intmain(void>
{
//声明所需变量;
DWORDwait_for_all。
ifstreaminFile。
//初始化缓冲区;
for(inti=0。
ii++>
Buffer_Critical[i]=-1。
//初始化每个线程的请求队列;
for(intj=0。
jj++>{
for(intk=0。
kk++>
Thread_Info[j].thread_request[k]=-1。
Thread_Info[j].n_request=0。
}
//初始化临界区;
for(i=0。
ii++>
InitializeCriticalSection(&PC_Critical[i]>。
//打开输入文件,按照规定的格式提取线程等信息;
inFile.open("test1.txt">。
//从文件中获得实际的缓冲区的数目;
inFile>>n_Buffer_or_Critical。
inFile.get(>。
printf("输入文件是:
\n">。
//回显获得的缓冲区的数目信息;
printf("%d\n",(int>n_Buffer_or_Critical>。
//提取每个线程的信息到相应数据结构中;
while(inFile>{
inFile>>Thread_Info[n_Thread].serial。
inFile>>Thread_Info[n_Thread].entity。
inFile>>Thread_Info[n_Thread].delay。
charc。
inFile.get(c>。
while(c!
='\n'&&!
inFile.eof(>>{
inFile>>Thread_Info[n_Thread].thread_request[Thread_Info[n_Thread].n_request++]。
SixE2yXPq5
inFile.get(c>。
}
n_Thread++。
}
//回显获得的线程信息,便于确认正确性;
for(j=0。
j<(int>n_Thread。
j++>{
intTemp_serial=Thread_Info[j].serial。
charTemp_entity=Thread_Info[j].entity。
doubleTemp_delay=Thread_Info[j].delay。
printf("\nthread%2d%c%f",Temp_serial,Temp_entity,Temp_delay>。
6ewMyirQFL
intTemp_request=Thread_Info[j].n_request。
for(intk=0。
kk++>
printf("%d",Thread_Info[j].thread_request[k]>。
kavU42VRUs
cout<}
printf("\n\n">。
//创建在模拟过程中几个必要的信号量
empty_semaphore=CreateSemaphore(NULL,n_Buffer_or_Critical,n_Buffer_or_Critical,y6v3ALoS89
"semaphore_for_empty">。
h_mutex=CreateMutex(NULL,FALSE,"mutex_for_update">。
M2ub6vSTnP
//下面这个循环用线程的ID号来为相应生产线程的产品读写时所
//使用的同步信号量命名;
for(j=0。
j<(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(>>。
0YujCfmUCw
}
//创建生产者和消费者线程;
for(i=0。
i<(int>n_Thread。
i++>{
if(Thread_Info[i].entity=='P'>
h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE>(Produce>,eUts8ZQVRd
&(Thread_Info[i]>,0,NULL>。
else
h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE>(Consume>,sQsAEJkW5T
&(Thread_Info[i]>,0,NULL>。
}
//主程序等待各个线程的动作结束;
wait_for_all=WaitForMultipleObjects(n_Thread,h_Thread,TRUE,-1>。
GMsIasNXkA
printf("\n\n全部生产者和消费者都已完成它们的工作.\n">。
printf("按任意键返回!
\n">。
_getch(>。
return0。
}
//确认是否还有对同一产品的消费请求未执行;
boolIfInOtherRequest(intreq>
{
for(inti=0。
ii++>
for(intj=0。
jj++>
if(Thread_Info[i].thread_request[j]==req>
returnTRUE。
returnFALSE。
}
//找出当前可以进行产品生产的空缓冲区位置;
intFindProducePosition(>
{
intEmptyPosition。
for(inti=0。
ii++>
if(Buffer_Critical[i]==-1>{
EmptyPosition=i。
//用下面这个特殊值表示本缓冲区正处于被写状态;
Buffer_Critical[i]=-2。
break。
}
returnEmptyPosition。
}
//找出当前所需生产者生产的产品的位置;
intFindBufferPosition(intProPos>
{
intTempPos。
for(inti=0。
ii++>
if(Buffer_Critical[i]==ProPos>{
TempPos=i。
break。
}
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>。
TIrRGchYzg
Sleep(m_delay>。
//开始请求生产
printf("生产者%2d发送生产请求信号.\n",m_serial>。
//确认有空缓冲区可供生产,同时将空位置数empty减1;用于生产者和消费者的同步;
wait_for_semaphore=WaitForSingleObject(empty_semaphore,-1>。
7EqZcWLZNX
//互斥访问下一个可用于生产的空临界区,实现写写互斥;
wait_for_mutex=WaitForSingleObject(h_mutex,-1>。
intProducePos=FindProducePosition(>。
ReleaseMutex(h_mutex>。
//生产者在获得自己的空位置并做上标记后,以下的写操作在生产者之间可以并发;
//核心生产步骤中,程序将生产者的ID作为产品编号放入,方便消费者识别。
printf("生产者%2d开始在缓冲区%2d生产产品.\n",m_serial,ProducePos>。
lzq7IGf02E
Buffer_Critical[ProducePos]=m_serial。
printf("生产者%2d完成生产过程:
\n",m_serial>。
printf("缓冲区[%2d]:
%3d\n",ProducePos,Buffer_Critical[ProducePos]>。
zvpgeqJ1hk
//使生产者写的缓冲区可以被多个消费者使用,实现读写同步;
ReleaseSemaphore(h_Semaphore[m_serial],n_Thread,NULL>。
NrpoJac3v1
}
//消费者进程
voidConsume(void*p>
{
//局部变量声明;
DWORDwait_for_semaphore,m_delay。
intm_serial,m_requestNum。
//消费者的序列号和请求的数目;1nowfTG4KI
intm_thread_request[MAX_THREAD_NUM]。
//本消费线程的请求队列;
//提取本线程的信息到本地;
m_serial=((ThreadInfo*>(p>>->serial。
m_delay=(DWORD>(((ThreadInfo*>(p>>->delay*INTE_PER_SEC>。
fjnFLDa5Zo
m_requestNum=((ThreadInfo*>(p>>->n_request。
for(inti=0。
ii++>
m_thread_request[i]=((ThreadInfo*>(p>>->thread_request[i]。
tfnNhnE6e5
Sleep(m_delay>。
//循环进行所需产品的消费
for(i=0。
ii++>{
//请求消费下一个产品
printf("消费者%2d请求消费%2d产品\n",m_serial,m_thread_request[i]>。
HbmVN777sL
//如果对应生产者没有生产,则等待;如果生产了,允许的消费者数目-1;实现了读写同步;
wait_for_semaphore=WaitForSingleObject(h_Semaphore[m_thread_request[i]],-1>。
V7l4jRB8Hs
//查询所需产品放到缓冲区的号
intBufferPos=FindBufferPosition(m_thread_request[i]>。
83lcPA59W9
//开始进行具体缓冲区的消费处理,读和读在该缓冲区上仍然是互斥的;
//进入临界区后执行消费动作;并在完成此次请求后,通知另外的消费者本处请求已
//经满足;同时如果对应的产品使用完毕,就做相应处理;并给出相应动作的界面提
//示;该相应处理指将相应缓冲区清空,并增加代表空缓冲区的信号量;
EnterCriticalSection(&PC_Critical[BufferPos]>。
printf("消费者%2d开始消费%2d产品\n",m_serial,m_thread_request[i]>。
mZkklkzaaP
((ThreadInfo*>(p>>->thread_request[i]=-1。
if(!
IfInOtherRequest(m_thread_request[i]>>{
Buffer_Critical[BufferPos]=-1。
//标记缓冲区为空;
printf("消费者%2d成功消费%2d:
\n",m_serial,m_thread_request[i]>。
AVktR43bpw
printf("缓冲区[%2d]:
%3d\n",BufferPos,Buffer_Critical[BufferPos]>。
ORjBnOwcEd
ReleaseSemaphore(empty_semaphore,1,NULL>。
}
else{
printf("消费者%2d成功消费产品%2d\n",m_serial,m_thread_request[i]>。
2MiJTy0dTT
}
//离开临界区
LeaveCriticalSection(&PC_Critical[BufferPos]>。
}
}
申明:
所有资料为本人收集整理,仅限个人学习使用,勿做商业用途。