操作系统原理实验报告最终版.docx
《操作系统原理实验报告最终版.docx》由会员分享,可在线阅读,更多相关《操作系统原理实验报告最终版.docx(31页珍藏版)》请在冰豆网上搜索。
操作系统原理实验报告最终版
操作系统原理实验报告(最终版)
XX学校
实验报告
课程名称:
学院:
专业班:
姓名:
学号:
指导教师:
2011年3月
实验1进程管理
一、实验目的
1.弄清进程和程序的区别,加深对进程概念的理解。
2.了解并发进程的执行过程,进一步认识并发执行的实质。
3.掌握解决进程互斥使用资源的方法。
二、实验内容
1.管道通信
使用系统调用pipe()建立一个管道,然后使用系统调用fork()创建2个子进程p1和p2。
这2个子进程分别向管道中写入字符串:
“Childprocessp1issendingmessage!
”和“Childprocessp2issendingmessage!
”,而父进程则从管道中读出来自两个子进程的信息,并显示在屏幕上。
2.软中断通信
使用系统调用fork()创建2个子进程p1和p2,在父进程中使用系统调用signal()捕捉来自键盘上的软中断信号SIGINT(即按Ctrl-C),当捕捉到软中断信号SIGINT后,父进程使用系统调用kill()分别向2个子进程发出软中断信号SIGUSR1和SIGUSR2,子进程捕捉到信号后分别输出信息“Childprocessp1iskilledbyparent!
”和“Childprocessp2iskilledbyparent!
”后终止。
而父进程等待2个子进程终止后,输出信息“Parentprocessiskilled!
”后终止。
三、实验要求
1.根据实验内容编写C程序。
2.上机调试程序。
3.记录并分析程序运行结果。
四、程序说明和程序流程图
实验1管道通信——所涉及的流程图:
实验2软中断信号——所涉及的流程图:
五、程序代码
/*expe1_1.c*/
#include
voidmain()
{
inti,r,p1,p2,fd[2];
charbuf[50],s[50];
pipe(fd);/*父进程建立管道*/
while((p1=fork())==-1);/*创建子进程P1,失败时循环*/
if(p1==0)/*由子进程P1返回,执行子进程P1*/
{
lockf(fd[1],1,0);/*加锁锁定写入端*/
sprintf(buf,"ChildprocessP1issendingmessages!
\n");
printf("ChildprocessP1!
\n");
write(fd[1],buf,50);/*把buf中的50个字符写入管道*/
sleep(5);/*睡眠5秒,让父进程读*/
lockf(fd[1],0,0);/*释放管道写入端*/
exit(0);/*关闭P1*/
}
else/*从父进程返回,执行父进程*/
{
while((p2=fork())==-1);/*创建子进程P2,失败时循环*/
if(p2==0)/*从子进程P2返回,执行子进程P2*/
{
lockf(fd[1],1,0);/*锁定写入端*/
sprintf(buf,"ChildprocessP2issendingmessages!
\n");
printf("ChildprocessP2!
\n");
write(fd[1],buf,50);/*把buf中的字符写入管道*/
sleep(5);/*睡眠5秒,让父进程读*/
lockf(fd[1],0,0);/*释放管道写入端*/
exit(0);/*关闭P2*/
}
wait(0);
if((r=read(fd[0],s,50))==-1)
printf("cannotreadpipe!
\n");
elseprintf("%s",s);
wait(0);
if((r=read(fd[0],s,50))==-1)
printf("cannotreadpipe!
\n");
elseprintf("%s",s);
exit(0);
}
}
/*exp1-2.c*/
#include
#include
#include
intp1,p2;
voidmain()
{
voidppdo();
voidp1do();
voidp2do();
signal(SIGINT,ppdo);
p1=fork();
if(p1==0)
{
signal(SIGUSR1,p1do);
for(;;);
}
else{
p2=fork();
if(p2==0){
signal(SIGUSR2,p2do);
for(;;);
}
}
wait(0);
wait(0);
printf("\nParentprocessiskilled!
\n");
exit(0);
}
voidppdo()
{
kill(p1,SIGUSR1);
kill(p2,SIGUSR2);
}
voidp1do()
{
printf("\nChildprocessp1iskilledbyparent!
\n");
exit(0);
}
voidp2do()
{
printf("\nChildprocessp2iskilledbyparent!
\n");
exit(0);
}
六、程序运行结果及分析
实验1管道通信运行结果截图
实验1管道通信结果分析
父进程建立后,创建了子进程P1,P2,然后P1,P2分别向管道中写入字符串“Childprocessp1issendingmessage!
”和“Childprocessp2issendingmessage!
”,父进程从管道中读取字符串。
实验2软中断通信运行结果截图
实验2软中断通信结果分析
先预设中断信号SIGINT,再先后创建子进程P1和P2,预设中断信号SIGUSR1,SIGUER2,当我们按下“Ctrl+C”时,父进程发出中断信号SIGUSR1和SIGUSR2,通知子进程P1和P2,子进程捕捉到信号后分别输出相应的信息后,终止,最后输出“Parentprocessiskilled!
”后终止。
实验后思考:
通过这次实验,深刻地了解到了管道通信和软中断通信的详细过程,深化了老师课堂上的讲解,对整个过程的把握也更加清晰了。
很值得的一次学习经历,做完实验,再画流程图,程序运行的细节熟悉于心,了如指掌。
七.指导教师评议
成绩等级
实验2进程通信
一、实验目的
1.了解进程间通信IPC的三种方式:
消息队列、共享内存和信号量。
2.掌握使用消息队列进行进程间通信的有关系统调用和编程方法。
3.掌握使用共享内存进行进程间通信的有关系统调用和编程方法。
二、实验内容
1.消息队列
使用系统调用msgget()、msgsnd()、msgrcv()和msgctl(),用消息队列机制实现客户进程和服务器进程间的通信。
客户进程首先建立一个描述符为msgqid的消息队列,接着向服务器进程发送一个消息正文为自己的进程标识pid且类型为1的消息,然后接收来自服务器进程的消息,并在屏幕上显示:
“Clientreceivesamessagefromxxxx!
”,其中“xxxx”为服务器进程的进程标识。
服务器进程首先捕捉软中断信号(除不能捕捉的SIGKILL),若捕捉到时则调用函数cleanup()删除消息队列,终止服务器进程。
否则重复下列操作:
接收所有类型为1的消息,并在屏幕上显示:
“Serverreceivesamessagefromxxxx!
”,其中“xxxx”为客户进程的进程标识;然后服务器进程将客户进程的进程标识作为返回消息的类型,而将自己的进程标识作为消息正文发送给客户进程。
2.共享内存
使用系统调用shmget()、shmat()和shmctl(),用共享内存机制实现进程间的通信。
其中一个进程向共享内存中写入数据,另一个进程从共享内存中读出数据并显示在屏幕上。
三、实验要求
1.根据实验内容编写C程序。
2.上机调试程序。
3.记录并分析程序运行结果。
四、程序说明和程序流程图
实验1消息队列流程图
五、程序代码
实验1消息队列
/*msg_client.c*/
#include
#include
#include
#defineMSGKEY75
structmsgform
{
longmtype;
charmtext[256];
}
main()
{
structmsgformmsg;
intmsgqid,pid,*pint;/*文件主同组用户其他用户rwxrwxrwx*/
msgqid=msgget(MSGKEY,0777);/*rw-rw-rw-*/
pid=getpid();
pint=(int*)msg.mtext;
*pint=pid;
msg.mtype=1;
msgsnd(msgqid,&msg,sizeof(int),0);
msgrcv(msgqid,&msg,256,pid,0);
printf("client:
receivefrompid%d\n",*pint);
}
/*msg_server.c*/
#include
#include
#include
#defineMSGKEY75
structmsgform
{longmtype;
charmtext[256];}msg;
intmsgqid;
main()
{
inti,pid,*pint;
externcleanup();
for(i=0;i<20;i++)
signal(i,cleanup);
msgqid=msgget(MSGKEY,0777|IPC_CREAT);
for(;;)
{msgrcv(msgqid,&msg,256,1,0);
pint=(int*)msg.mtext;
pid=*pint;
printf("server:
receivefrompid%d\n",pid);
msg.mtype=pid;
*pint=getpid();
msgsnd(msgqid,&msg,
sizeof(int),0);}}
cleanup()
{
msgctl(msgqid,IPC_RMID,0);
exit(0);
}
实验2共享内存
#include
#include
#include
#defineSHMKEY75
#defineK1024
intshmid;
main()
{
inti,*pint;
char*addr;
externchar*shmat();
shmid=shmget(SHMKEY,8*K,0777);
addr=shmat(shmid,0,0);
pint=(int*)addr;
while(*pint==0)
for(i=0;i<256;*pint++)
printf("%d\n",*pint++);
}
#include
#include
#include
#defineSHMKEY75
#defineK1024
intshmid;
main()
{
inti,*pint;
char*addr;
externchar*shmat();
externcleanup();
for(i=0;i<20;i++)
sinal(i,cleanup);
shmid=shmget(SHMKEY,16*K,0777|IPC_CREAT);
addr=shmat(shmid,0,0);
printf("addr0x%x\n",addr);
pint=(int*)addr;
for(i=0;i<256;i++)
*pint++=i;
pint=(int*)addr;
*pint=256;
pause();
}
cleanup()
{
shmctl(shmid,IPC_RMID,0);
exit(0);
}
六、程序运行结果及分析
实验1消息队列运行结果截图
客户端:
服务器端:
实验1消息队列结果分析
服务端程序监听软中断,建立消息队列,循环在队列中接收类型为1的消息,每接收一个消息向队列中增加一个类型为客户进程ID的消息。
当发生软中断时,删除消息队列。
客户端进程创建和服务端相同的消息队列,并向消息队列中发送类型为1的消息,然后接收类型为客户进程ID的消息。
实验后思考:
对消息队列的运行情况有所了解,但关于内存共享部分尚需仔细研究。
七.指导教师评议
成绩等级
实验3存储管理
一、实验目的
1.了解虚拟存储管理技术的原理与特点。
2.掌握请求页式存储管理的页面置换算法。
二、实验内容
1.通过随机数产生一个指令序列,共320条指令。
指令的地址按下述原则生成:
(1)50%的指令是顺序执行的;
(2)25%的指令均匀分布在前地址部分;
(3)25%的指令均匀分布在后地址部分。
实现方法:
(1)在[0,319]的指令地址中随机选取一起点s;
(2)执行指令s;
(3)顺序执行一条指令,即执行地址为s+1的指令;
(4)在前地址[0,s]中随机选取一条地址为m的指令执行;
(5)顺序执行一条指令,即执行地址为m+1的指令;
(6)在后地址[m+2,319]中随机选取一条指令s;
(7)重复
(2)—(6),直到执行320次指令。
2.将指令序列变换为页地址流,设:
(1)页面大小为1K;
(2)用户内存容量为4—32页面(pageframe);
(3)用户虚存容量为32K(即32页)。
若10条指令为1页,则320条指令在虚存中的存放方式为:
第0页(虚存地址[0,9])——第0条~第9条指令;
第1页(虚存地址[10,19])——第10条~第19条指令;
••••••
第31页(虚存地址[310,319])——第310条~第319条指令。
3.计算并输出下列算法在不同内存容量下的命中率(命中率=1-缺页率)。
(1)FIFO——FirstInFirstOutPageReplacementAlgorithm
(2)LRU——LeastRecentlyUsedPageReplacementAlgorithm
三、实验要求
1.根据实验内容编写C程序。
2.上机调试程序。
3.记录并分析程序运行结果。
四、程序说明和程序流程图
程序说明为:
1.通过随机数产生一个指令序列,共320条指令。
指令的地址按下述原则生成:
(1)50%的指令是顺序执行的;
(2)25%的指令均匀分布在前地址部分;
(3)25%的指令均匀分布在后地址部分。
实现方法:
(1)在[0,319]的指令地址中随机选取一起点s;
(2)执行指令s;
(3)顺序执行一条指令,即执行地址为s+1的指令;
(4)在前地址[0,s]中随机选取一条地址为m的指令执行;
(5)顺序执行一条指令,即执行地址为m+1的指令;
(6)在后地址[m+2,319]中随机选取一条指令s;
(7)重复
(2)—(6),直到执行320次指令。
2.将指令序列变换为页地址流,设:
(1)页面大小为1K;
(2)用户内存容量为4—32页面(pageframe);
(3)用户虚存容量为32K(即32页)。
若10条指令为1页,则320条指令在虚存中的存放方式为:
第0页(虚存地址[0,9])——第0条~第9条指令;
第1页(虚存地址[10,19])——第10条~第19条指令;
••••••
第31页(虚存地址[310,319])——第310条~第319条指令。
3.计算并输出下列算法在不同内存容量下的命中率(命中率=1-缺页率)。
(1)FIFO——FirstInFirstOutPageReplacementAlgorithm
(2)LRU——LeastRecentlyUsedPageReplacementAlgorithm
流程图:
五、程序代码
#include
#include
//#include/*Windows环境,getpid()原型在process.h中*/
#defineTRUE1
#defineFALSE0
#defineINVALID-1
#defineNULL0
#definetotal_instruction320/*指令条数*/
#definetotal_vp32/*虚页数*/
#defineclear_period50/*NRU清0周期*/
typedefstruct{/*页表结构*/
intpn,pfn,counter,time;/*counter(LFU),time(LRU)*/
}pl_type;
pl_typepl[total_vp];/*页表*/
structpfc_struct{/*存储页面表*/
intpn,pfn;
structpfc_struct*next;
};
typedefstructpfc_structpfc_type;
pfc_typepfc[total_vp],*freepf_head,*busypf_head,*busypf_tail;
intdiseffect,a[total_instruction];/*缺页次数,指令流*/
intpage[total_instruction],offset[total_instruction];
voidinitialize(int);
voidfifo(int);
voidlru(int);
voidopt(int);voidlfu(int);voidnur(int);
voidmain()
{
ints,i,j;
srand(getpid()*10);/*进程标识作为随机数种子*/
s=(float)319*rand()/2147483647;/*0~319*/
//s=(float)319*rand()/32767;/*0~319*/
for(i=0;i{a[i]=s;/*s=0~319*/
a[i+1]=a[i]+1;/*s+1*/
a[i+2]=(float)a[i]*rand()/2147483647;/*m=0~s*/
//a[i+2]=(float)a[i]*rand()/32767;/*m=0~s*/
a[i+3]=a[i+2]+1;/*m+1*/
s=(float)rand()*(317-a[i+2])/2147483147+a[i+2]+2;/*m+2~319*/
//s=(float)rand()*(317-a[i+2])/32767+a[i+2]+2;/*m+2~319*/
}
for(i=0;i{
page[i]=a[i]/10;
offset[i]=a[i]%10;
}
for(i=4;i<=32;i++)/*用户内存工作区4-32个页面*/
{
printf("%2dpageframes",i);
fifo(i);
lru(i);
opt(i);lfu(i);nur(i);
printf("\n");
}
}
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;
}
for(i=1;i{
pfc[i-1].next=&pfc[i];pfc[i-1].pfn=i-1;
}
pfc[total_pf-1].next=NULL;
pfc[total_pf-1].pfn=total_pf-1;
freepf_head=&pfc[0];
}
voidfifo(inttotal_pf)
{
inti,j;
pfc_type*p;
initialize(total_pf);
busypf_head=busypf_tail=NULL;/*置忙页面队列为空*/
for(i=0;iif(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;
/*释放忙队列中的第1个页面(淘汰1页),即出队*/
freepf_head->next=NULL;
busypf_head=p;/*插入到空闲页面链表*/
}
p=freepf_head->next;