作系统》课程实验指导Word下载.docx
《作系统》课程实验指导Word下载.docx》由会员分享,可在线阅读,更多相关《作系统》课程实验指导Word下载.docx(16页珍藏版)》请在冰豆网上搜索。
2、内容
⑴在后备作业队列中,输入5个作业各自运行所需要的时间及存储空间。
①按先来先服务的原则进行调度,输出作业调度的顺序及等待的时间。
②按最短作业(即运行时间最短)优先的原则进行调度,输出作业调度的顺序及等待时间。
③按最小作业(即存储空间最小)优先的原则进行调度,输出作业调度的顺序及等待的时间。
根据运行情况,比较各种算法。
⑵在后备作业队列中,先输入5个作业各自运行所需要的时间,然后每输入一个作业的运行时间,就按响应比高优先的原则进行调度,直到输入作业的运行时间为0时,依次输出响应比高的其它作业。
3、要求
⑴对输入的每个作业必须编号,输出时要有作业序号、运行时间、存储空间及等待时间(包括总的等待时间);
⑵实验报告中的运行情况要包括输入和输出情况;
⑶比较上面几种调度算法的优劣。
4、思路
⑴输入格式:
要求有序号、运行时间、存储空间。
例:
numruntimestorage
12030
24015
35090
42010
53560
⑵输出格式:
要求有序号、运行时间、存储空间、等待时间及总的等待时间,并注明是何种调度。
FCFS
numruntimestoragewaittime
120300
2401520
3509060
42010110
53560130
Thewholewaitingtimeis:
320
⑶响应比Rp=1+作业等待时间/运行时间
运行时首先输出5个作业中运行时间最短的作业,然后每输入一个作业,计算响应比,输出最高者。
输入要求有序号、运行时间;
输出要求有序号、运行时间、等待时间。
5、举例
建主程序、三个子程序(例如:
先来先服务FCFS、最短作业优先LSFS、最短运行时间作业优先SRFS)、打印程序及原始数据。
五个作业运行时间,建文件DATA.DAT,其中包含num、runtime、storage、waittime和Thewaitingtime。
6、作业调度流程图示例
存储管理的主要功能之一是合理地分配存储空间。
请求页式存储管理是常用的虚拟存储技术。
本实验的目的是通过请求页式管理中页面置换算法了解虚拟存储技术的特点,掌握请求页式存储管理的页面置换算法。
⑴通过随机数产生一个指令序列,共320条指令。
指令的地址按下述原则生成:
①一半的指令是顺序执行的;
②四分之一的指令是均匀分布在前地址部分;
③四分之一的指令是均匀分布在前地址部分。
具体的实施办法是:
①在[0,319]之间选一起点m;
②顺序执行一条指令,即m+1条;
③向前地址[0,m—1]中执行一条指令m'
;
④顺序执行一条指令,即m'
+1条;
⑤向后地址(m'
+2,319]执行一条指令m'
'
⑵将指令序列变换成为页地址流。
假设:
①页面大小为1KB;
②用户实寸容量为4页到32页;
③用户虚存容量为32KB。
用户虚存容量32KB,每1KB中放10条指令,共320条指令(0~319)。
其中0~9为0页,10~19为1页…310~319为31页。
⑶使用不同的页面调度算法处理缺页中断,并计算不同实存容量下(4~32KB)的命中率。
①先进先出算法(FIFO);
②最近最少使用算法(LRU);
③最佳淘汰算法(OPT);
先淘汰最不常用的页地址;
④最少访问页面算法(LFU)。
命中率的算法为:
命中率=缺页中断次数/页地址流长度
⑴实验报告中要有程序的详细框图,特别是有关算法本身的框图;
⑵实验报告中要有程序清单及执行的结果;
⑶对不同算法的性能进行评价。
关于随机数的产生办法。
首先要初始化设置随机数,产生序列的开始点,例如,通过下列语句实现:
srand(400)
⑴计算随机数,产生320条指令序列
m=160
for(i=0;
i<
80;
i++)
{
j=i*4;
a[j]=m;
a[j+1]=m+1;
a[j+2]=a[j]*1.0*rand()/32767;
a[j+3]=a[j+2]+1;
m=a[j+3]+(319-a[j+3]*1.0*rand()/32767;
}
⑵将指令序列变换成为页地址流
for(k=0;
k<
320;
k++)
{pt=a[k]/10;
…
⑶计算不同算法的命中率
rate=1—1.0*U/320;
其中U为缺页中断次数,320是页地址流长度。
⑷输出格式
kfifolru
40.230.25
………
321.01.0
5、页面调度模拟算法流程图示例
(1)
6、页面调度模拟算法流程图示例
(2)
通过进程的创建、控制和通讯的设计达到下述目的:
⑴加深对进程概念的理解,明确进程和程序的区别;
⑵进一步认识并发(共行)执行的概念,区别顺序执行和并发(共行)执行;
⑶分析进程争用临界资源的现象,学习解决进程互斥的方法;
⑷了解UNIX或Linux系统中进程通讯的基本原理。
⑴进程的创建
编制一段程序,使用系统调用fork()创建两个子进程,这样在此程序运行时,在系统中就有一个父进程和两个自进程在活动。
让每一个进程在屏幕上显示一个字符:
父进程显示字符a,自进程分别显示字符b和字符c。
试观察、记录并分析屏幕上进程调度的情况。
如果在程序中使用系统调用nice()来改变各进程的优先级,会出现什么现象?
⑵进程的控制
修改已编制的程序,将每个进程输出一个字符修改为每个进程输出一句话,再观察程序执行时屏幕上出现的现象。
并分析出现问题的原因。
进一步理解各个进程争夺临界资源的情况。
如果在程序中使用系统调用locking()来给每一个进程加锁,可以实现进程之间的互斥,试观察并分析出现的现象。
⑶进程的软中断通讯
编制一段程序,实现进程的软中断通讯:
使用系统调用fork()创建两个子进程;
再使用系统调用。
signal()让父进程捕捉键盘上来的中断信号(即按Del键);
在捕捉到中断信号后,父进程用系统调用kill()向两个子进程发信号;
子进程捕捉到信号后分别输出下列信息后终止:
childprocess1iskilledbyparent!
childprocess2iskilledbyparent!
父进程等待两个子进程都终止以后,输出如下信息后终止。
parentprocessinkilled!
⑷进程的管道通讯
编制一段程序,实现进程的管道通讯:
使用系统调用pipe()建立一条管道线;
两个子进程分别循环向这条管道写一句话:
child1issendingamessage!
child2issendingamessage!
而父进程则循环从管道中读出信息,显示在屏幕上。
用管道进行通讯,实质上是一个多生产者单消费者的问题,必须考虑其中都有哪些同步和互斥,同时向管道输入端写的字节数必须和从输出端读的字节数一致,若不一致,则会出现什么问题。
⑴仔细观察实验中的各种现象及出现的问题。
分析产生各种现象的原因。
寻找解决问题的办法。
⑵实验报告应至少包括带注释的程序清单、输出的结果及对各种现象的分析意见。
4、思考
⑴系统调用fork()是怎样创建进程的?
⑵当首次调用新创建的子进程时,其入口在哪里?
⑶为什么各进程占用的处理机时间不等?
⑷进程通讯有什么特点?
⑸含有进程调用的程序与没有进程调用的程序在执行过程中有什么不同?
如何体现进程的动态特征?
5、进程管理实验内容示例
(1)用4个基本系统调用实现进程的创建、执行和自我终止:
①fork()。
创建一个子进程。
用它创建的子进程是fork调用者进程(即父进程)的复制品,即进程映象。
除了进程标识数以及与进程特性有关的一些参数外,其它与父进程相同,与父进程共享文本段和打开的文件,并都受进程调度程序的调度。
如果创建进程失败,则fork()返回值为-1:
若创建进程成功,则从父进程返回值是子进程号,从子进程返回的值是0,返回值在R0。
m=fork()。
②wait()。
父进程处于阻塞(或等待)状态,等待子进程执行完成终止后继续工作。
其返回值R0为等待子进程的子进程号。
n=wait()。
③exit()。
子进程自我终止,释放所占资源,通知父进程可以删除自己。
此时它的状态变成P_state=SZOMB。
④getpid()。
获得进程的标识数(进程号),一般是正整数。
P=getpid()。
编程示例:
例1、编写一个程序,父进程生成一个子进程,父进程等待子进程wait(),子进程执行完成后自我终止exit(),并唤醒父进程。
父、子进程执行时打印有关信息。
main()
{inti,j,k;
if(i=fork())//非零值
{j=wait();
printf(“Parentprocess!
\n”);
printf(“i=%dk=%d\n,i,k);
else
{k=getpid();
printf(“Childprocess!
例2.编写一个程序,输入两个整数并求和输出,然后创建一个子进程,当进程调度程序调度到父进程或子进程时特输出不同的信息。
{inti,j,k,sum;
scanf(“%d%d”,&
j,&
k);
sum=j+k;
printf(“sum=%d\n”,sum);
while((i=jork())==-1)
printf(“i=%d\n,i);
if(i)printf(“Itisparentprocess!
elseprintf(“ItisChildprocess!
实验题1.编写一个程序,用fork()创建2个子进程。
让每个进程在屏幕上显示一个字符:
父进程显示字符a,子进程分别显示字符b和字符c。
先对例1和例2进行运行,了解各个系统调用的使用,再做本实验题1。
观察、记录并分析屏幕上进程调度的情况。
(2)进程的“软中断”通信
它可用于同一用户的进程之间通信。
其方式是:
一个进程通过系统调用kill(pid,sig)向同一用户的其它进程pid发送一个软中断信号:
另一进程通过系统调用signal(sig,func)捕捉到信号sig后,执行予先约定的动作func,从而实现这两个进程间的通信。
①发送信号kill(pid,sig),本进程将指定信号sig发送给指定进程pid,其中参数为pid进程号,pid与sig均为整数值。
②接收信号signal(sig,func),本进程接收到其它进程发送给它的信号后,完成指定的功能func。
func一般是函数。
例3.编写一个程序,父进程生成子进程,父进程发送信号并等待,子进程接收信号并完成某种功能,然后自我终止并唤醒父进程。
intfunc();
{inti,j:
signal(17,func);
if(i=fork())
{printf(“Parent:
Signal17willbesendtoChild!
\n”);
kill(i,17);
wait(0);
printf(“Parent:
finished!
\n”)”
sleep(10);
printf(“Child:
AsignalfrommyParentisreceived!
\n”)
exit();
func()
{printf(“Itissignal17processingfunction!
\n”;
)
执行结果如下:
Parent:
Itissignal17processingfunction!
Child:
在程序中系统调用sleep(second)用于进程的同步与互斥,自变量是暂停秒数。
其功能是使现行进程暂停执行由自变量规定的秒数。
类似的系统调用有pause(),它的功能是暂停执行本进程,等待kill发来的信号,收到信号后再继续执行。
在特殊情况下,常用到如下语句signal(SIGINT,SIG_IGN)。
它表示遇到了中断信号SIGINT(按Del键)。
本进程不做任何动作,即勿略该中断信号对本进程的影响。
实验题2.编写一个程序,实现进程的“软中断”通信。
使用系统调用fork()创建2个子进程,再使用系统调用signal()让父进程捕捉键盘上来的中断信号(即按Del键),在捕捉到中断信号后,父进程用系统调用kill()向2个子进程发信号,子进程捕捉到信号后分别输出下列信息后终止:
Childprocess1iskilledbyparent!
Childprocess3iskilledbyparent!
父进程等待2个子进程都终止后,输出如下信息后终止:
Parentprocessiskilled!
(3)进程的控制
利用系统调用locking(fd,mode,size),对指定文件的指定区域(由size指示)进行加锁或解锁,以实现进程的同步与互斥。
其中fd是文件描述字;
mode是锁定方式,=1表示加锁,=0表示解锁,size是指定文件fd的指定区域,用0表示从当前位置到文件尾。
常用程序段
fd=open(“a.out”,2);
i=fork();
if(i==0)
{locking(fd,1,0);
………
locking(fd,0,0);
例4.编写一个程序,创建一个文件,文件名为lock.dat,同时父进程创建2个子进程,通过系统调用locking(),分别让2个子进程对文件加锁,再输出有关信息,然后解锁。
charbuf[]={“checklock!
\n”};
{inti,p1,p2,fd;
fd=creat(“lock.dat”,0644);
write(fd,buf,20);
while((p1=fork())==-1);
if(p1==0)
for(i=1;
i<=3;
i++=
printf(“child1!
{while((p2=fork())==-1);
if(p2==0)
i<=4;
printf(“child2!
elseprintf(“parrent!
close(fd);
实验题3.编写一个程序,用系统调用fork()创建2个子进程。
让每个进程输出一句话。
并利用系统调用locking在各进程执行时摈制加锁。
观察程序执行时屏幕上出现的现象,并说明原因。
(注:
有的系统中locking()形式是lockf()。
(4)进程管道的通信
建立进程间的管道,格式为:
pipe(fd);
intfd[2];
其中,fd[1]是写端,向管道中写入;
fd[0]是读端,从管道中读出;
本质上将其当作文件处理。
进程间可通过管道,用write与read来传递数据,但write与read不可以同时进行,在管道中只能有4096字节的数据被缓冲。
例5.编写一个程序,建立一个pipe,同时父进程产生一个子进程,子进程向pipe中写入一个字符串,父进程从中读出该字符串,并每隔3秒种输出打印一次。
{intx,fd{2};
charS[30];
for(;
;
{x=fork();
if(x==0)
{sprintf(S,”Good-night!
write(fd[1],S,20);
sleep(3);
exit(0);
{wait(0);
read(fd[0],S,20);
printf(“**********\n”,S);
实验题4.编写一段程序,实现进程的管道通信。
使用系统调用pipe()建立一条子管道线,2个子进程分别循环向这条管道写一句话:
child1issendingamessage!
Child2issendingamessage!
1.基本思想
可变分区是指系统不预先划分固定分区,而是在装入程序的时候划分内存区域,使得为程序分配的分区大小恰好等于该程序的需求量,且分区的个数是可变的。
显然可变分区有较大的灵活性,较之固定分区能获得好的内存利用率。
2.数据结构
可变分区管理可以用两种数据结构实现,一种是已分配区表和空闲区表,也就是用预先定义好的系统空间来存放空间分配信息。
请参见教材P101页图4-10。
另一种也是最常用的就是空闲链表,由于对分区的操作是动态的,所以很难估计数据结构所占用的空间,而且空闲区表会占用宝贵的系统空间,所以提出了空闲链表的概念。
其特点是用于管理分区的信息动态生成并和该分区在物理地址上相邻。
这样由于可以简单用两个空闲块之间的距离定位已分配空间,不仅节约了系统空间,而且不必维持已分配空间的信息,。
下图是空闲链表的示意图。
3.实习要求
请同学们实现一个完整的可变分区管理器,包括分配,回收,分区碎片整理等。
希望同学们考虑如下问题:
⏹
容错性,当操作出现错误,比如空间不足,空指针引用等的情况下的处理。
空闲块的合并。
已分配空间的跟踪。
当做碎片整理时,需要跟踪分配的空间,修改其引用以保证引用的正确性。