南昌大学操作系统实验报告Word格式.docx
- 文档编号:5111616
- 上传时间:2023-05-04
- 格式:DOCX
- 页数:42
- 大小:312.80KB
南昌大学操作系统实验报告Word格式.docx
《南昌大学操作系统实验报告Word格式.docx》由会员分享,可在线阅读,更多相关《南昌大学操作系统实验报告Word格式.docx(42页珍藏版)》请在冰点文库上搜索。
父线程(主线程)定义两个全局变量,比如accnt1和accnt2。
每个变量表示一个银行账户,其值表示该账户的存款余额,初始值为0。
线程模拟在两个账户之间进行转账的交易。
也即,每个线程首先读取两个账户的余额,然后产生一个随机数r,在其中一个账户上减去该数,在另一个账户上加上该数。
线程操作的代码框架如下:
counter=0;
do{
tmp1=accnt1;
tmp2=accnt2;
r=rand();
accnt1=tmp1+r;
accnt2=tmp2−r;
counter++;
}while(accnt1+accnt2==0);
print(counter);
两个线程执行相同的代码。
只要它们的执行过程不相互交叉,那么两个账户的余额之和将永远是0。
但如果发生了交叉,那么某线程就有可能读到新的accnt1值和老的accnt2值,从而导致账户余额数据发生混乱。
线程一旦检测到混乱的发生,便终止循环并打印交易的次数(counter)。
请编写出完整的程序代码并运行,然后观察产生混乱需要的时间长短。
因为这是我们编写的第一个程序,因此这里我给出了完整的代码,请参考。
有能力的同学在参考下面的代码之前,请先自己尝试一下。
#include<
stdio.h>
stdlib.h>
windows.h>
intaccnt1=0;
intaccnt2=0;
DWORDWINAPIrun(LPVOIDp){
intcounter=0;
inttmp1,tmp2,r;
counter++;
printf(”%d\n”,counter);
}
intmain(intargc,char∗argv[])
{
CreateThread(NULL,
0,
run,
NULL,
NULL);
system(“PAUSE”);
return0;
反复运行该程序。
请问,观察到了什么?
你能解释这些现象吗?
2.2临界区问题之解决方案
上面例子中,线程执行的代码叫做临界区,因为两个线程在这里访问了同样的数据,
在没有保护的情况下,有可能发生混乱。
解决该问题有两套方案。
其一,如果操作系统提
供了同步原语,例如mutex,那么就可直接利用该原语对临界区进行排它性的存取保护。
其
二,如果操作系统不提供这样的原语,那么可用软件方案加以解决。
本实验中,我们将实
现并比较这两种方案。
2.2.1mutex方案
Windows操作系统提供了mutex对象。
mutex状态可以是signaled(unlocked)或者是nonsignaled(locked)。
利用mutex对象,可以方便地实现临界区保护。
进入临界区时(在第一个读操作之前),锁住mutex对象;
离开临界区时(在第二个写操作之后),打开mutex对象。
线程的阻塞与唤醒由系统管理,程序员无需干预。
以下给出的是在Windows操作系统下有关mutex对象操作的提示。
创建一个未上锁mutex对象的代码如下:
HANDLEhMutex=CreateMutex(NULL,
FALSE,
给mutex对象上锁的代码如下:
WaitForSingleObject(hMutex,INFINITE);
打开mutex对象的代码如下:
ReleaseMutex(hMutex);
根据以上提示,编写出用mutex对象保护临界区的解决方案。
完成后,请思考以下问题:
假设把加锁和开锁操作分别放置在第一个写操作之前和第二个写操作之后,能否实现临界区的保护,为什么?
2.2.2软件方案
现在假设操作系统没有提供同步原语。
这时,我们只能通过编程语言对变量的操作实现临界区保护。
下面给出的是一个概念性的解决方案框架:
intc1=0,c2=0,willwait;
cobegin
p1:
while
(1){
c1=1;
willwait=1;
while(c2&
&
(willwait==1));
/∗waitloop∗/
CS1;
c1=0;
program1;
p2:
c2=1;
willwait=2;
while(c1&
(willwait==2));
CS2;
c2=0;
program2;
上面的方案使用了三个变量c1,c2和willwait。
线程i试图进入临界区时首先把变量ci置为1,接着把变量willwait的值设置为i(为什么?
)阻塞通过临界区之前的循环实现。
当线程退出临界区时,又把变量ci的值设置为0。
在我们的例子中,临界区始于第一个读操作,结束于第二个写操作。
请把上面的概念框架转换为可运行的C代码,实现临界区的保护。
为了加快程序的执行速度,可在阻塞循环中增加一个Sleep(0)语句。
这可以让不能进入临界区的线程马上放弃处理器,而不用无谓消耗处理器资源。
最后,请比较mutex方案和软件方案的效率(执行相同的循环次数,计算消耗的时间。
为了让结果更科学,请多次试验,然后计算平均值)。
提示:
时间度量可以用
DWORDGetTickCount(VOID)
在操作开始之前调用一次,操作结束之后再调用一次,两次调用所得到的返回值的差便是该操作所消耗的大致时间(单位毫秒)。
3、实验代码、数据及处理结果
#include"
stdafx.h"
int_tmain(intargc,_TCHAR*argv[])
return0;
windows.h>
intcounter=0;
accnt2=tmp2-r;
printf("
循环1次数为%d\n"
counter);
printf("
%d,%d\n\n"
accnt1,accnt2);
return0;
CreateThread(NULL,0,run,NULL,0,NULL);
system("
PAUSE"
);
}
由运行结果可观察出,当没有任何线程同步机制时,程序无法循环多次。
原因是没有线程同步机制。
2.21mutex方案
doublebegin=0;
doubleend=0;
doubletime=0;
inta=1;
HANDLEhMutex=CreateMutex(NULL,FALSE,NULL);
}while(accnt1+accnt2==0&
counter<
1000000);
循环%d次数为%d\n"
a,counter);
end=GetTickCount();
time=end-begin;
printf("
进程%d所用时间为%d\n"
a,time);
a++;
ReleaseMutex(hMutex);
由运行结果可观察出,当采用mutex方法时,两进程所运行的时间大致是相同的,进程运行完全,有效地防止了两进程相互交叉以及障碍。
2.22
DWORDWINAPIrun1(LPVOIDp){
doublebegin=0,end=0,time=0;
begin=GetTickCount();
循环次数为%d\n"
进程1所用时间为%d\n"
time);
DWORDWINAPIrun2(LPVOIDp){
counter);
进程2所用时间为%d\n"
boolc1=false,c2=false;
intwillwait;
while
(1);
{
c1=true;
willwait=1;
while(c1&
(willwait=1))
CreateThread(NULL,0,run1,NULL,0,NULL);
break;
}
c1=0;
break;
while
(1);
c2=true;
willwait=2;
while(c2&
(willwait=2))
CreateThread(NULL,0,run2,NULL,0,NULL);
c2=0;
system("
);
由运行结果可观察出,该步骤并不能使进程解锁。
由于前后两次结果有执行到最后的也有迅速调试出结果的,因此该做法并不稳定。
四、实验体会或对改进实验的建议
将OS中引入进程可以提高了资源的利用率和系统的吞吐量,但是同时也会给系统造成混乱。
进程同步是对多个相关进程在执行次序上进行协调,以使并发执行的诸进程之间能有效地共享资源和相互合作,从而使程序的执行具有可再现性。
mutex机制实现了由一个进程对公共资源进行访问的时候,不允许其它进程对此资源进行访问,它保证了进程之间的互斥性。
2014-5-23实验成绩:
实验2编程实现银行家安全算法
死锁会引起计算机工作僵死,因此操作系统中必须防止。
本实验的目的在于让学生独立的使用高级语言编写和调试一个系统动态分配资源的简单模拟程序,了解死锁产生的条件和原因,并采用银行家算法有效地防止死锁的发生,以加深对课堂上所讲授的知识的理解。
二、实验要求
设计有n个进程共享m个系统资源的系统,进程可动态的申请和释放资源,系统按各进程的申请动态的分配资源。
系统能显示各个进程申请和释放资源,以及系统动态分配资源的过程,便于用户观察和分析;
四、实验步骤
1、分析银行家算法结构;
2、画出银行家算法的流程图,即设计说明;
3、根据画出的流程图使用C语言编写相应的代码
4、检查代码,将编出的代码编译、链接,验证其正确性。
五、算法流程、实验代码和实验结果
iostream>
usingnamespacestd;
#defineFalse0
#defineTrue1
intMax[100][100]={0};
intAllocation[100][100]={0};
intNeed[100][100]={0};
intAvailable[100]={0};
intWork[100]={0};
charname[100]={0};
inttemp[100]={0};
intS=100,P=100;
intsafequeue[100]={0};
intRequest[100]={0};
//
voidShowdata()
inti,j,k,l;
cout<
<
"
\t资源分配情况\n"
endl;
\tMax"
\t已分配"
\tNeed"
\t"
;
for(j=0;
j<
3;
j++)
for(i=0;
i<
S;
i++)
{
cout<
name[i]<
"
}
cout<
for(i=0;
P;
for(j=0;
Max[i][j]<
for(k=0;
k<
k++)
Allocation[i][k]<
for(l=0;
l<
l++)
Need[i][l]<
\nAvailable"
for(i=0;
Available[i]<
intJudgesafe()
inttempwork[100][100]={0};
inti,x,k=0,m,apply,Finish[100]={0};
intj;
intflag=0;
Work[i]=Available[i];
{
apply=0;
for(j=0;
if(Finish[i]==False&
Need[i][j]<
=Work[j])
{
apply++;
if(apply==S)
{
for(m=0;
m<
m++)
{
tempwork[i][m]=Work[m];
Work[m]=Work[m]+Allocation[i][m];
}
Finish[i]=True;
temp[k]=i;
i=-1;
k++;
flag++;
}
}
if(Finish[i]==False)
系统不安全"
return-1;
系统是安全的"
分配的序列:
temp[i];
if(i<
P-1)cout<
->
voidChangedata(intflag)
for(inti=0;
Available[i]=Available[i]-Request[i];
Allocation[flag][i]=Allocation[flag][i]+Request[i];
Need[flag][i]=Need[flag][i]-Request[i];
voidShare()
inti,flag;
charch='
Y'
输入请求资源的进程:
cin>
>
flag;
if(flag>
=P)
此进程不存在!
else
输入此进程对各个资源的请求数量:
cin>
Request[i];
if(Request[i]>
Need[flag][i])
{
cout<
进程"
flag<
申请的资源大于它所需要的资源!
分配不合理不予分配!
ch='
N'
break;
elseif(Request[i]>
Available[i])
申请的资源大于可利用的资源。
分配不合理,不予分配!
if(ch=='
)
Changedata(flag);
if(Judgesafe()==-1)
申请资源后,系统进入死锁状态,分配失败!
for(inti=0;
Available[i]=Available[i]+Request[i];
Allocation[flag][i]=Allocation[flag][i]
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 南昌大学 操作系统 实验 报告