操作系统实验报告Word下载.docx
《操作系统实验报告Word下载.docx》由会员分享,可在线阅读,更多相关《操作系统实验报告Word下载.docx(21页珍藏版)》请在冰豆网上搜索。
![操作系统实验报告Word下载.docx](https://file1.bdocx.com/fileroot1/2023-2/3/4ce765e3-88f3-4ece-94df-1c960c0421e6/4ce765e3-88f3-4ece-94df-1c960c0421e61.gif)
//缓冲区是个循环队列
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=3;
//生产者的个数
constunsignedshortCONSUMERS_COUNT=1;
//消费者的个数
//总的线程数
constunsignedshortTHREADS_COUNT=PRODUCERS_COUNT+CONSUMERS_COUNT;
HANDLEhThreads[PRODUCERS_COUNT];
//各线程的handle
DWORDproducerID[CONSUMERS_COUNT];
//生产者线程的标识符
DWORDconsumerID[THREADS_COUNT];
//消费者线程的标识符
//创建生产者线程
for(inti=0;
i<
PRODUCERS_COUNT;
++i){
hThreads[i]=CreateThread(NULL,0,Producer,NULL,0,&
producerID[i]);
if(hThreads[i]==NULL)return-1;
}
//创建消费者线程
CONSUMERS_COUNT;
hThreads[PRODUCERS_COUNT+i]=CreateThread(NULL,0,Consumer,NULL,0,&
consumerID[i]);
while(g_continue){
if(getchar()){//按回车后终止程序运行
g_continue=false;
return0;
}
//生产一个产品。
简单模拟了一下,仅输出新产品的ID号
voidProduce()
std:
:
cerr<
<
"
Producing"
<
++ProductID<
..."
;
Succeed"
endl;
//把新生产的产品放入缓冲区
voidAppend()
Appendingaproduct..."
g_buffer[in]=ProductID;
in=(in+1)%SIZE_OF_BUFFER;
//输出缓冲区当前的状态
SIZE_OF_BUFFER;
cout<
i<
"
g_buffer[i];
if(i==in)std:
--生产"
if(i==out)std:
--消费"
//从缓冲区中取出一个产品
voidTake()
Takingaproduct..."
ConsumeID=g_buffer[out];
out=(out+1)%SIZE_OF_BUFFER;
//消耗一个产品
voidConsume()
Consuming"
ConsumeID<
//生产者
DWORDWINAPIProducer(LPVOIDlpPara)
WaitForSingleObject(g_hFullSemaphore,INFINITE);
WaitForSingleObject(g_hMutex,INFINITE);
Produce();
Append();
Sleep(1500);
ReleaseMutex(g_hMutex);
ReleaseSemaphore(g_hEmptySemaphore,1,NULL);
//消费者
DWORDWINAPIConsumer(LPVOIDlpPara)
WaitForSingleObject(g_hEmptySemaphore,INFINITE);
Take();
Consume();
ReleaseSemaphore(g_hFullSemaphore,1,NULL);
五、实验总结
生产者消费者算法是一个经典的进程同步算法,我所采用的纪录型信号量解决的此问题。
算法的思想比较简单,但是实现起来不容易。
特别是要模拟两个进程,一个生产,一个消费比较困难。
为了解决此问题,我特地学习了Windows下使用C++如何创造线程,从而控制生产-消费的过程。
通过本实验,我更加深入地了解了生产者-消费者算法,同时也学会了如何应用信号量机制来同步进程。
实验二银行家算法
通过实验使学生进一步了解资源安全分配的算法。
基本能达到下列具体的目标:
1.理解死锁概念,以及死锁产生的必要条件。
2.理解银行家算法基本原理。
3.掌握一种资源和多种资源的银行家算法的设计与实现。
1.设计出管理的资源种类和数量
2.设计出银行家算法的基本数据结构
3.设计出完成该资源的银行家算法
4.设计出简单的进程创建、运行资源需求、结束的过程
//银行家算法
#include<
iomanip>
#defineMAX_PROCEDURE_NUM5
#defineRESOURCE_TYPE_NUM1
usingnamespacestd;
classProcedure
public:
//private:
intRequest[RESOURCE_TYPE_NUM];
//public:
intSentReq(intj){returnRequest[j];
};
classBanker
intAvailable[RESOURCE_TYPE_NUM];
intmax[MAX_PROCEDURE_NUM][RESOURCE_TYPE_NUM];
intAllocation[MAX_PROCEDURE_NUM][RESOURCE_TYPE_NUM];
intNeed[MAX_PROCEDURE_NUM][RESOURCE_TYPE_NUM];
boolApplyResource(Procedure&
p,intProID);
//分配资源函数
boolSafetyCheck(intResourceNum);
//检测系统安全性函数
voidPrintTable();
//输出系统的资源分配情况
boolBanker:
ApplyResource(Procedure&
p,intProID)
for(intj=0;
j<
RESOURCE_TYPE_NUM;
j++)
{
if(p.SentReq(j)<
=Need[ProID][j])
{
if(p.SentReq(j)<
=Available[j])
{
intPreAvailable,PreAllocation,PreNeed;
PreAvailable=Available[j];
PreAllocation=Allocation[ProID][j];
PreNeed=Need[ProID][j];
//先暂存以前的值
Available[j]=Available[j]-p.SentReq(j);
Allocation[ProID][j]=Allocation[ProID][j]+p.SentReq(j);
Need[ProID][j]=Need[ProID][j]-p.SentReq(j);
if(!
SafetyCheck(j))//ifnot,rollback
{
Available[j]=PreAvailable;
Allocation[ProID][j]=PreAllocation;
Need[ProID][j]=PreNeed;
cout<
分配不安全!
}
elsecout<
分配成功!
}
else{cout<
资源不足!
returnfalse;
}
}
else{cout<
申请过大!
SafetyCheck(intResourceNum)
intwork[RESOURCE_TYPE_NUM];
//系统供给进程继续运行所需的各类资源数目
for(inti=0;
i++)work[i]=Available[i];
//算法开始时,work:
=Available
boolFinish[MAX_PROCEDURE_NUM];
//表示系统是否有足够的资源分配给进程,使之运行完成
MAX_PROCEDURE_NUM;
i++)Finish[i]=false;
//刚开始时初始化为false
i++)
if(Finish[i]==false&
&
Need[i][ResourceNum]<
=work[ResourceNum])
work[ResourceNum]=work[ResourceNum]+Allocation[i][ResourceNum];
Finish[i]=true;
i=0;
continue;
//一旦有新资源产生就重新扫描
i++)
if(Finish[i]==false)returnfalse;
//一旦有一个进程不能完成,返回false
returntrue;
//所有进程满足安全状态,返回true
voidBanker:
PrintTable()
cout.setf(ios:
internal);
cout.width(10);
cout<
Procedure"
cout.width(10*RESOURCE_TYPE_NUM);
Max"
cout.width(10*RESOURCE_TYPE_NUM);
Allo"
Need"
cout<
'
\n'
'
for(inta=0;
a<
3;
a++)
for(intb=0;
b<
b++)
{cout.width(10);
char('
A'
+b);
a++)
cout.width(10);
P"
a;
for(intb=0;
b++)
{cout.width(10);
max[a][b];
Allocation[a][b];
Need[a][b];
cout<
Available"
b++){cout.width(10);
Available[b];
\n\n\n"
Procedureprc;
//假设ProID是1
prc.Request[0]=1;
Bankerbnk;
bnk.Available[0]=10;
bnk.max[0][0]=7;
bnk.max[1][0]=3;
bnk.max[2][0]=9;
bnk.max[3][0]=2;
bnk.max[4][0]=4;
bnk.Allocation[0][0]=0;
bnk.Allocation[1][0]=2;
bnk.Allocation[2][0]=3;
bnk.Allocation[3][0]=2;
bnk.Allocation[4][0]=0;
bnk.Need[0][0]=7;
bnk.Need[1][0]=1;
bnk.Need[2][0]=6;
bnk.Need[3][0]=0;
bnk.Need[4][0]=4;
bnk.PrintTable();
bnk.ApplyResource(prc,1);
getchar();
这次实验总体的完成过程比较顺利,得益于一开始就设计好数据结构,省去了很多麻烦。
通过这次实验,我加深了解有关资源申请、避免死锁等概念,并体会了解决死锁和避免死锁的具体实施方法。
实验三页面置换算法
进一步理解父子进程之间的关系。
1.理解内存页面调度的机理。
2.掌握页面置换算法的实现方法。
3.通过实验比较不同调度算法的优劣。
4.培养综合运用所学知识的能力。
页面置换算法是虚拟存储管理实现的关键,通过本次试验理解内存页面调度的机制,在模拟实现FIFO、LRU等经典页面置换算法的基础上,比较各种置换算法的效率及优缺点,从而了解虚拟存储实现的过程。
将不同的置换算法放在不同的子进程中加以模拟,培养综合运用所学知识的能力。
这是一个综合型实验,要求在掌握父子进程并发执行机制和内存页面置换算法的基础上,能综合运用这两方面的知识,自行编制程序。
程序涉及一个父进程和两个子进程。
父进程使用rand()函数随机产生若干随机数,经过处理后,存于一数组Acess_Series[]中,作为内存页面访问的序列。
两个子进程根据这个访问序列,分别采用FIFO和LRU两种不同的页面置换算法对内存页面进行调度。
要求:
1.每个子进程应能反映出页面置换的过程,并统计页面置换算法的命中或缺页情况。
设缺页的次数为diseffect。
总的页面访问次数为total_instruction。
缺页率=disaffect/total_instruction
命中率=1-disaffect/total_instruction
2.将为进程分配的内存页面数mframe作为程序的参数,通过多次运行程序,说明FIFO算法存在的Belady现象。
四、实验程序代码
stdio.h>
sys/types.h>
stdlib.h>
sys/stat.h>
fcntl.h>
error.h>
wait.h>
unistd.h>
main()
intp1,p2;
inti,j,k,t,m,kk,r1,r2;
inttemp1,temp2,temp3;
intdiseffect1=0;
intdiseffect2=0;
intk1=0;
intk2=0;
intf1=0;
intf2=0;
floatf;
intAccess_series[8];
structone_frame{
intpage_no;
charflag;
};
intmframe=5;
structone_frameM_Frame[5];
for(i=0;
mframe;
i++)M_Frame[i].page_no=-1;
printf("
yemian:
);
8;
i++)//产生随机数
{Access_series[i]=rand()%8+1;
%d"
Access_series[i]);
}printf("
\n"
while((p1=fork())==-1);
if(p1==0)
for(j=0;
{r1=Access_series[j];
//读入一个逻辑页面
for(k=0;
k<
k1;
k++)//查找页面是否已存在于物理页面
{if(r1!
=M_Frame[k].page_no)continue;
else
{printf("
havefound!
i++)//存在则显示,并标记,返回读入逻辑页面
printf("
M_Frame[i]);
printf("
f1=1;
break;
}}
if(f1==0)
{diseffect1++;
//若不存在,发生缺页,则失效率加1
if(k1<
mframe)//物理页面没有分配满
M_Frame[k1].page_no=r1;
//分配一个空的物理页面
M_Frame[k1].flag='
Y'
k1++;
for(i=0;
i++)printf("
printf("
diseffect!
%d\n"
diseffect1);
for(i=0;
else
{temp1=M_Frame[0].page_no;
//物理