操作系统实验报告.docx
《操作系统实验报告.docx》由会员分享,可在线阅读,更多相关《操作系统实验报告.docx(46页珍藏版)》请在冰豆网上搜索。
操作系统实验报告
操作系统实验报告
学生姓名刘杰
学号12101020128
班级计12-1班
实验名称
实验1进程管理
实验序号
实验日期
2014\12\4
实验人
刘杰
一、实验目的和要求
(1)加深对进程概念的理解,明确进程和程序的区别
(2)进一步认识并发执行的实质
(3)分析进程争用资源的现象,学习解决进程互斥的方法
(4)了解Linux系统中进程通信的基本原理
二、相关背景知识
1、进程的创建,阻塞,唤醒以及终止
2、进程同步
3、进程通信
三、实验内容
1、进程的创建
编写一段程序,使用系统调用fork()创建两个子进程。
当此程序运行时,在系统中有一个父进程和两个子进程活动。
让每一个进程在屏幕上显示一个字符:
父进程显示字符“a”;子进程分别显示字符“b”和字符“c”。
试观察记录屏幕上的显示结果,并分析原因。
2、进程的控制
修改已有程序,将每个进程输出一个字符改为每个进程输出几行字符,再观察程序执行时屏幕上的现象,并分析原因。
如果在程序中使用系统调用lockf()来给每一个进程加锁,可以实现进程之间的互斥,观察并分析出现的现象。
3、进程的软中断通信
使用系统调用fork()创建两个子进程,再用系统调用signal()让父进程捕捉键盘上来的中断信号(即按Del键);当捕捉到中断信号后,父进程用系统调用kill()向两个子进程发出信号,子进程捕捉到信号后分别输出下列信息后终止:
Childprocess1iskilledbyparent!
Childprocess2iskilledbyparent!
父进程等待两个子进程终止后,输出如下的信息后终止:
Parentprocessiskilled!
4、进程的管道通信
编制一段程序,实现进程的管道通信。
使用系统调用pipe()建立一条管道线;两个子进程P1和P2分别向管道各写一句话:
Child1issendingamessage!
Child2issendingamessage!
而父进程则从管道中读出来自于两个子进程的信息,显示在屏幕上。
要求父进程先接收P1发来的消息,然后再接收P2发来的消息。
四、关键数据结构与函数的说明
fork()函数
通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。
lockf()函数
允许将文件区域用作信号量(监视锁),或用于控制对锁定进程的访问(强制模式记录锁定)。
试图访问已锁定资源的其他进程将返回错误或进入休眠状态,直到资源解除锁定为止。
当关闭文件时,将释放进程的所有锁定,即使进程仍然有打开的文件。
当进程终止时,将释放进程保留的所有锁定。
wait()函数
进程一旦调用了wait(),就立即阻塞自己,由wait()自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。
kill()函数
kill()函数用于结束执行中的程序或者任务。
signal()函数
signal()会依参数signum指定的信号编号来设置该信号的处理函数。
当指定的信号到达时就会跳转到参数handler指定的函数执行。
当一个信号的信号处理函数执行时,如果进程又接收到了该信号,该信号会自动被储存而不会中断信号处理函数的执行,直到信号处理函数执行完毕再重新调用相应的处理函数。
但是如果在信号处理函数执行时进程收到了其它类型的信号,该函数的执行就会被中断。
pipe()函数
pipe函数用于创建一个管道Fork()函数。
五、编译与执行过程截图
程序1:
进程创建
程序2:
进程控制,未使用lockf()函数
程序2:
使用lockf()函数
程序3:
进程软中断通信
程序4:
管道通信
六、实验结果与分析
1.分析:
从进程执行并发来看,输出bac,acb等情况都有可能。
原因:
fork()创建进程所需的时间多于输出一个字符的时间,因此在主进程创建进程2的同时,进程1就输出了“b”,而进程2和主程序的输出次序是有随机性的,所以会出现上述结果。
2.1分析:
由于函数printf()输出的字符比较多,由于进程并发执行时的调度顺序和父子进程的抢占处理机问题,输出字符串的顺序和先后随着执行的不同而发生变化。
这与打印单字符的结果相同。
2.2分析:
虽然函数printf()输出的字符比较多,但由于进程间使用lockf()函数,输出不会被中断,输出字符串的顺序和进程执行顺序保持一致。
4.
(1)首先要判断读写进程双方是否存在,只有确定读进程和写进程都存在的情况下,才能够通过管道进行通信。
(2)同步:
当写进程完成任务,把要求的数据写入管道后,便会睡眠等待。
直到读进程将管道中的数据读取取出后,再把写进程唤醒。
当读进程试图从一空管道中读取数据时,也应睡眠等待,直至写进程将数据写入管道后,才将其唤醒。
(3)互斥:
当一个进程正对pipe进行读/写操作时,另一进程必须等待,程序中使用lock(fd[1],1,0)函数实现对管道的加锁操作,用lock(fd[1],0,0)解除管道的锁定.
七、调试时遇到的问题及解决方法
遇到问题:
1.程序1的输出不符合理论输出
2.程序3执行结果不对
解决办法:
询问同学,网上查阅资料
八、调试后的程序源代码
1、进程创建:
#include
intmain()
{
inti,p1,p2;
if(p1=fork())
printf("b");
else
if(p2=fork())
printf("c");
else
printf("a");
return0;
}
2、进程控制
#include
intmain()
{
inti,p1,p2;
if(p1=fork())
{
//lockf(1,1,0);
printf("b0bobobobobobobobobobobobobobobo\n");
printf("b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1\n");
printf("b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2\n");
//lockf(1,0,0);
}
else
if(p2=fork())
{
//lockf(1,1,0);
printf("c0c0c0c00c0c0c0c0c0c0c0c0c0cc0\n");
printf("c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1\n");
printf("c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2\n");
//lockf(1,0,0);
}
else
{//lockf(1,1,0);
printf("a0a0a0a0a0a0a0a0a0a0a0a0a0a0a\n");
printf("a1a1a1a1a1a1a1a1aa1a1a1a1a1a1a\n");
printf("a2a2a22a2a2a2a2a2a2a2a2a2a2a2a\n");
//lockf(1,0,0);
}
return0;
}
3、进程软中断通信
#include
#include
#include
#include
#include
#include
#include
#include
voidgo();
voidstop1(),stop2();
pid_tp1,p2;
voidmain()
{
intstatus=-1;
intrtv;
while((p1=fork())==-1);/*创建子进程p1*/
if(p1>0)
{
while((p2=fork())==-1);/*创建子进程p2*/
if(p2>0)
{
signal(SIGINT,go);/*接收到信号,转go*/
pause();
sleep
(2);
wait(NULL);
wait(NULL);
printf("Parentprocessiskilled!
\n");
exit(0);
}
else
{
signal(SIGINT,SIG_IGN);//屏蔽默认的SIGINT信号处理
signal(SIGUSR2,stop2);
if(signal(SIGUSR2,stop2)==SIG_ERR){
printf("Can'tcatchSIGUR2");
}
pause();
printf("Process2End\n");
}
}
else
{
signal(SIGINT,SIG_IGN);
if(signal(SIGUSR1,stop1)==SIG_ERR){
printf("Can'tcatchSIGUR2");
}
pause();
printf("Process1End\n");
}
}
voidgo()
{
intrtv;
rtv=kill(p1,SIGUSR1);/*向p1发软中断信号16*/
rtv=kill(p2,SIGUSR2);/*向p2发软中断信号17*/
}
voidstop2()
{
printf("Childprocess2iskilledbyparent!
\n");
exit(0);
}
voidstop1()
{
printf("Childprocess1iskilledbyparent!
\n");
exit(0);
}
4、进程管道通信
#include
#include
#include
intpid1,pid2;
voidmain()
{
inth=0;
intfd[2];
charoutpipe[100],inpipe[100];
pipe(fd);/*创建一个管道*/
while((pid1=fork())==-1);
if(pid1==0)
{
lockf(fd[1],1,0);
sprintf(outpipe,"child1processissendingmessage!
");/*把串放入数组outpipe中*/
write(fd[1],outpipe,50);/*向管道写长为50字节的串*/
sleep
(1);/*自我阻塞1秒*/
lockf(fd[1],0,0);
exit(0);
}
else
{
while((pid2=fork())==-1);
if(pid2==0)
{
lockf(fd[1],1,0);/*互斥*/
sprintf(outpipe,"child2processissendingmessage!
");
write(fd[1],outpipe,50);
sleep(5);
lockf(fd[1],0,0);
exit(0);
}
else
{
wait(0);/*同步*/
read(fd[0],inpipe,50);/*从管道中读长为50字节的串*/
printf("%s\n",inpipe);
wait(0);
read(fd[0],inpipe,50);
printf("%s\n",inpipe);
exit(0);
}
}
}
9、实验体会
这一次实验,使我对进程相关知识有了更深刻的认识,加深了我对操作系统中进程管理的理解,尤其是进程的创建,运行,控制,同步以及进程间的通信。
纸上得来终觉浅,所有的理论在未经实践检验之前都仅仅是写在书本上或是死记硬背在脑子里的文字,只有经历了实践,理论才能真正的被理解。
实验名称
实验2、存储管理
实验序号
实验日期
2014\12\11
实验人
刘杰
一、实验目的和要求
1.通过请求页式存储管理中页面置换算法的模拟设计,了解虚拟存储技术的特点,掌握请求页式存储管理的页面置换算法。
二、相关背景知识
1、虚拟存储的相关知识
2、请求分页存储管理方式的相关知识
3、请求调页机制的相关知识
4、FIFO算法和LRU算法
5、缺页率计算
三、实验内容
(1).通过随机数产生一个指令序列,共320条指令。
指令的地址按下述原则生成:
1.50%的指令是顺序执行的;
2.25%的指令是均匀分布在前地址部分;
3.25%的指令是均匀分布在后地址部分;
具体的实施方法是:
1.在[0,319]的指令地址之间随机选取一起点m;
2.顺序执行一条指令,即执行地址为m+1的指令;
3.在前地址[0,m+1]中随机选取一条指令并执行,该指令的地址为m’;
4.顺序执行一条指令,其地址为m’+1;
5.在后地址[m’+2,319]中随机选取一条指令并执行;
6.重复上述步骤1~5,直到执行320次指令。
(2)将指令序列变换成页地址流,设
1.页面大小为1K;
2.用户内存容量为4页到32页;
3.用户虚存容量为32K。
在用户虚存中,按每K存放10条指令排列虚存地址,即320条指令在虚存中存放的方式为:
第0条至第9条指令为第0页(对应虚存地址为[0,9]);
第10条至第19条指令为第1页(对应虚存地址为[10,19]);
……
第310条至第319条指令为第31页(对应虚存地址为[310,319]);
按以上方式,用户指令可以组成32页。
(3)计算并输出下述各种算法在不同内存容量下的命中率。
1.先进先出页面淘汰算法(FIFO)
2.最近最久未使用页面淘汰法(LRU)
命中率=1-页面失效次数/页地址流长度
在本实验中,页地址流长度为320,页面失效次数为每次访问相应指令时,该指令对应的页不在内存的次数。
四、关键数据结构与函数的说明
typedefstruct/*页面结构*/
{
intpn,pfn,counter,time;
}pl_type;
pl_typepl[total_vp];/*页面结构数组*/
structpfc_struct{/*页面控制结构*/
intpn,pfn;
structpfc_struct*next;
};
voidinitialize();//初始化
voidFIFO();//先进先出页面置换算法
voidLRU();//最久未使用页面置换算法
五、编译与执行过程截图
六、实验结果与分析
总体上,不管是先进先出算法还是最久未使用算法,随着叶框的增加,命中率也相应增加。
但也受指令执行顺序的影响,叶框增加,命中率并不一定提高。
另外,在相同的叶框下,最久未使用算法命中率总体上较先进先出算法稍高。
七、调试时遇到的问题及解决方法
遇到问题:
1.对完成该实验所需数据结构不清楚
2.进行页面切换时总是出错
解决办法:
查看相关知识,网上查资料,借鉴别人的做法
8、调试后的程序源代码
#include
#include
#include
#defineTRUE1
#defineFALSE0
#defineINVALID-1//页面调入标志
#definetotal_instruction320/*指令流长*/
#definetotal_vp32/*虚页长*/
#defineclear_period50/*清零周期*/
typedefstruct/*页面结构*/
{
intpn,pfn,counter,time;
}pl_type;
pl_typepl[total_vp];/*页面结构数组*/
structpfc_struct{/*页面控制结构*/
intpn,pfn;
structpfc_struct*next;
};
structpfc_structpfc[total_vp],*freepf_head,*busypf_head,*busypf_tail;
intdiseffect,a[total_instruction];
intpage[total_instruction],offset[total_instruction];
intmain()
{
intS,i;
srand(10*getpid());
S=(int)(319.0*rand()/RAND_MAX)+1;
for(i=0;i{
a[i]=S;/*任选一指令访问点*/
a[i+1]=a[i]+1;/*顺序执行下一条指令*/
a[i+2]=(int)(1.0*a[i]*rand()/RAND_MAX);/*执行前地址指令m'*/
a[i+3]=a[i+2]+1;/*执行后地址指令*/
S=(int)(1.0*rand()*(318-a[i+2])/RAND_MAX)+a[i+2]+2;
}
for(i=0;i{
page[i]=a[i]/10;
offset[i]=a[i]%10;
}
for(i=4;i<=32;i++)/*用户内存工作区从4个页面到32个页面*/
{
printf("%2dpageframes\t",i);
FIFO(i);
LRU(i);
}
return0;
}
voidinitialize(inttotal_pf)/*初始化相关数据结构*/
{
inti;
diseffect=0;
for(i=0;i{
pl[i].pn=i;
pl[i].pfn=INVALID;/*置页面控制结构中的页号,页面为空*/
pl[i].counter=0;pl[i].time=-1;/*置页面控制结构中的访问次数,时间为-1*/
}
for(i=1;i{
pfc[i-1].next=&pfc[i];
pfc[i-1].pfn=i-1;
}/*建立pfc[i-1]和pfc[i]之间的链接*/
pfc[total_pf-1].next=NULL;
pfc[total_pf-1].pfn=total_pf-1;
freepf_head=&pfc[0];/*空页面队列的头指针为pfc[0]*/
}
voidFIFO(inttotal_pf)
{
inti;structpfc_struct*p;
initialize(total_pf);/*初始化相关页面控制用数据结构*/
busypf_head=busypf_tail=NULL;/*忙页面队列,队列尾链接*/
for(i=0;i{
if(pl[page[i]].pfn==INVALID)/*页面失效*/
{
diseffect+=1;/*失效次数*/
if(freepf_head==NULL)/*无空闲页面*/
{
p=busypf_head->next;
pl[busypf_head->pn].pfn=INVALID;
freepf_head=busypf_head;/*释放忙页面队列中的第一个页面*/
freepf_head->next=NULL;
busypf_head=p;
}
p=freepf_head->next;/*按FIFO方式调新页面入内存页面*/
freepf_head->next=NULL;
freepf_head->pn=page[i];
pl[page[i]].pfn=freepf_head->pfn;
if(busypf_tail==NULL)
busypf_head=busypf_tail=freepf_head;
else{
busypf_tail->next=freepf_head;
busypf_tail=freepf_head;
}
freepf_head=p;
}
}
printf("FIFO:
%6.4f",1-(float)diseffect/320);
}
voidLRU(inttotal_pf)
{
intmin,minj,i,j,present_time;
initialize(total_pf);
present_time=0;
for(i=0;i{
if(pl[page[i]].pfn==INVALID)/*页面失效*/
{
diseffect+=1;/*失效次数*/
if(freepf_head==NULL)/*无空闲页面*/
{
min=32767;
for(j=0;jif(min>pl[j].time&&pl[j].pfn!
=INVALID)
{
min=pl[j].time;
minj=j;
}
freepf_head=&pfc[pl[minj].pfn];
pl[minj].pfn=INVALID;
pl[minj].time=-1;
freepf_head->next=NULL;
}
pl[page[i]].pfn=freepf_head->pfn;
pl[page[i]].time=present_time;
freepf_head=freepf_head-