作系统》课程实验指导.doc
操作系统课程实验指导·实验一 UNIX或Linux操作系统的实际使用·实验二 进程调度·实验三 作业调度设计·实验四 存储管理设计·实验五 进程管理设计·实验六 可变分区内存管理实验一 UNIX或Linux操作系统的实际使用1.目的通过本实验熟悉UNIX或Linux操作系统的命令操作使用2.内容参见Linux有关简要使用说明3.要求熟悉开机后登录进入系统和推出系统常用命令的操作使用全屏幕编译器vi的熟悉使用为以后的上机实验作好充分准备4.说明在有条件的学习环境,建议学员自己先学习Linux操作系统的安装,可以购买一张某一种品牌的相应Linux光盘,在PC机(甚至486机型都可以)上用Partition Magic这一类工具软件在硬盘上分出一块至少大于200MB以上的非DOS分区(原有硬盘上的重要软件数据最好事先做好备份),然后按照光盘上安装说明逐步进行。 返回 实验二 进程调度题目:单处理机系统的进程调度要求:用实验方法模拟单处理机系统的进程调度,并采用时间片轮转调度算法作为进程调度算法。预备知识:1、进程调度实现所涉及到的主要问题:如何组织进程、如何实现处理机调度。进程控制块的作用和结构,进程控制块的链表组织。进程调度程序包含从进程就绪队列选择并摘取进程、给该进程分配处理机。2、进程调度程序流程图: 返回 实验三 作业调度设计1、目的作业管理是用户与操作系统的接口。作业调度的主要功能是检查系统是否能满足用户作业的资源要求以及按照一定的算法选取作业。本实验的目的是通过模拟作业调度算法的设计加深对作业管理基本原理的理解。2、内容在后备作业队列中,输入5个作业各自运行所需要的时间及存储空间。按先来先服务的原则进行调度,输出作业调度的顺序及等待的时间。按最短作业(即运行时间最短)优先的原则进行调度,输出作业调度的顺序及等待时间。按最小作业(即存储空间最小)优先的原则进行调度,输出作业调度的顺序及等待的时间。根据运行情况,比较各种算法。在后备作业队列中,先输入5个作业各自运行所需要的时间,然后每输入一个作业的运行时间,就按响应比高优先的原则进行调度,直到输入作业的运行时间为0时,依次输出响应比高的其它作业。3、要求对输入的每个作业必须编号,输出时要有作业序号、运行时间、存储空间及等待时间(包括总的等待时间);实验报告中的运行情况要包括输入和输出情况;比较上面几种调度算法的优劣。4、思路输入格式:要求有序号、运行时间、存储空间。例:num runtime storage1 20 302 40 153 50 904 20 105 35 60输出格式:要求有序号、运行时间、存储空间、等待时间及总的等待时间,并注明是何种调度。例:FCFSnum runtime storage waittime1 20 30 02 40 15 203 50 90 604 20 10 1105 35 60 130The whole waiting time is:320响应比 Rp=1+作业等待时间/运行时间运行时首先输出5个作业中运行时间最短的作业,然后每输入一个作业,计算响应比,输出最高者。输入要求有序号、运行时间;输出要求有序号、运行时间、等待时间。5、举例建主程序、三个子程序(例如:先来先服务FCFS、最短作业优先LSFS、最短运行时间作业优先SRFS)、打印程序及原始数据。五个作业运行时间,建文件DATA.DAT,其中包含num、runtime、storage、waittime和The waiting time。6、作业调度流程图示例 返回 实验四 存储管理设计1、目的存储管理的主要功能之一是合理地分配存储空间。请求页式存储管理是常用的虚拟存储技术。本实验的目的是通过请求页式管理中页面置换算法了解虚拟存储技术的特点,掌握请求页式存储管理的页面置换算法。2、内容通过随机数产生一个指令序列,共320条指令。指令的地址按下述原则生成:一半的指令是顺序执行的;四分之一的指令是均匀分布在前地址部分;四分之一的指令是均匀分布在前地址部分。具体的实施办法是:在0,319之间选一起点m;顺序执行一条指令,即m+1条; 向前地址0,m1中执行一条指令m';顺序执行一条指令,即m'+1条;向后地址(m'+2,319执行一条指令m''将指令序列变换成为页地址流。假设:页面大小为1KB;用户实寸容量为4页到32页;用户虚存容量为32KB。用户虚存容量32KB,每1KB中放10条指令,共320条指令(0319)。其中09为0页,1019为1页310319为31页。使用不同的页面调度算法处理缺页中断,并计算不同实存容量下(432KB)的命中率。先进先出算法(FIFO);最近最少使用算法(LRU);最佳淘汰算法(OPT);先淘汰最不常用的页地址; 最少访问页面算法(LFU)。命中率的算法为:命中率=缺页中断次数/页地址流长度3、要求实验报告中要有程序的详细框图,特别是有关算法本身的框图;实验报告中要有程序清单及执行的结果;对不同算法的性能进行评价。4、思路关于随机数的产生办法。首先要初始化设置随机数,产生序列的开始点,例如,通过下列语句实现:srand(400)计算随机数,产生320条指令序列m=160for(i=0;i<80;i+)j=i*4;aj=m;aj+1=m+1;aj+2=aj*1.0*rand( )/32767;aj+3=aj+2+1;m=aj+3+(319-aj+3*1.0*rand( )/32767;将指令序列变换成为页地址流for (k=0;k<320;k+)pt=ak/10;计算不同算法的命中率rate=11.0*U/320;其中U为缺页中断次数,320是页地址流长度。输出格式k fifo lru4 0.23 0.25 32 1.0 1.05、页面调度模拟算法流程图示例(1)6、页面调度模拟算法流程图示例(2) 返回 实验五 进程管理设计1、目的通过进程的创建、控制和通讯的设计达到下述目的:加深对进程概念的理解,明确进程和程序的区别;进一步认识并发(共行)执行的概念,区别顺序执行和并发(共行)执行;分析进程争用临界资源的现象,学习解决进程互斥的方法;了解UNIX或Linux系统中进程通讯的基本原理。2、内容进程的创建编制一段程序,使用系统调用fork( )创建两个子进程,这样在此程序运行时,在系统中就有一个父进程和两个自进程在活动。让每一个进程在屏幕上显示一个字符:父进程显示字符a,自进程分别显示字符 b和字符c。试观察、记录并分析屏幕上进程调度的情况。如果在程序中使用系统调用nice( )来改变各进程的优先级,会出现什么现象?进程的控制修改已编制的程序,将每个进程输出一个字符修改为每个进程输出一句话,再观察程序执行时屏幕上出现的现象。并分析出现问题的原因。进一步理解各个进程争夺临界资源的情况。如果在程序中使用系统调用locking( )来给每一个进程加锁,可以实现进程之间的互斥,试观察并分析出现的现象。进程的软中断通讯编制一段程序,实现进程的软中断通讯:使用系统调用fork( )创建两个子进程;再使用系统调用。signal( )让父进程捕捉键盘上来的中断信号(即按Del键);在捕捉到中断信号后,父进程用系统调用kill( )向两个子进程发信号;子进程捕捉到信号后分别输出下列信息后终止:child process1 is killed by parent!child process2 is killed by parent!父进程等待两个子进程都终止以后,输出如下信息后终止。parent process in killed!进程的管道通讯编制一段程序,实现进程的管道通讯:使用系统调用pipe( )建立一条管道线;两个子进程分别循环向这条管道写一句话:child 1 is sending a message!child 2 is sending a message!而父进程则循环从管道中读出信息,显示在屏幕上。用管道进行通讯,实质上是一个多生产者单消费者的问题,必须考虑其中都有哪些同步和互斥,同时向管道输入端写的字节数必须和从输出端读的字节数一致,若不一致,则会出现什么问题。3、要求仔细观察实验中的各种现象及出现的问题。分析产生各种现象的原因。寻找解决问题的办法。实验报告应至少包括带注释的程序清单、输出的结果及对各种现象的分析意见。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()int i,j,k;if (i=fork() / 非零值j=wait();printf(“Parent process!n”);printf(“i=%d k=%dn,i,k);elsek=getpid();printf(“Child process!n”);printf(“i=%d k=%dn,i,k);例2.编写一个程序,输入两个整数并求和输出,然后创建一个子进程,当进程调度程序调度到父进程或子进程时特输出不同的信息。main()int i,j,k,sum;scanf(“%d%d”,&j,&k);sum=j+k;printf(“sum=%dn”,sum);while(i=jork()=-1)printf(“i=%dn,i);if (i) printf(“It is parent process!n”);else printf(“It is Child process!n”);实验题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. 编写一个程序,父进程生成子进程,父进程发送信号并等待,子进程接收信号并完成某种功能,然后自我终止并唤醒父进程。int func();main()int i,j:signal(17,func);if(i=fork()printf(“Parent: Signal 17 will be send to Child! n”);kill(i,17);wait(0);printf(“Parent: finished! n”)”elsesleep(10);printf(“Child: A signal from my Parent is received! n”)exit();func()printf(“It is signal 17 processing function! n”;)执行结果如下:Parent: Signal 17 will be send to Child!It is signal 17 processing function!Child: A signal from my Parent is received!Parent: finished!在程序中系统调用sleep(second)用于进程的同步与互斥,自变量是暂停秒数。其功能是使现行进程暂停执行由自变量规定的秒数。类似的系统调用有pause(),它的功能是暂停执行本进程,等待kill发来的信号,收到信号后再继续执行。在特殊情况下,常用到如下语句signal(SIGINT,SIG_IGN)。它表示遇到了中断信号SIGINT(按Del键)。本进程不做任何动作,即勿略该中断信号对本进程的影响。实验题2. 编写一个程序,实现进程的“软中断”通信。使用系统调用fork()创建2个子进程,再使用系统调用signal()让父进程捕捉键盘上来的中断信号(即按Del键),在捕捉到中断信号后,父进程用系统调用kill()向2个子进程发信号,子进程捕捉到信号后分别输出下列信息后终止:Child process 1 is killed by parent !Child process 3 is killed by parent !父进程等待2个子进程都终止后,输出如下信息后终止:Parent process is killed !(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个子进程对文件加锁,再输出有关信息,然后解锁。char buf=“check lock!n”;main()int i,p1,p2,fd;fd=creat(“lock.dat”,0644);write(fd,buf,20);while(p1=fork()=-1);if(p1=0)locking(fd,1,0);for (i=1;i=3;i+printf(“child1!n”);locking(fd,0,0);elsewhile(p2=fork()=-1);if (p2=0)locking(fd,1,0);for (i=1;i=4;i+printf(“child2!n”);locking(fd,0,0);else printf(“parrent!n”);close(fd);实验题3. 编写一个程序,用系统调用fork()创建2个子进程。让每个进程输出一句话。并利用系统调用locking在各进程执行时摈制加锁。观察程序执行时屏幕上出现的现象,并说明原因。(注:有的系统中locking()形式是lockf()。)(4)进程管道的通信建立进程间的管道,格式为:pipe(fd);int fd2;其中,fd1 是写端,向管道中写入;fd0 是读端,从管道中读出;本质上将其当作文件处理。进程间可通过管道,用write与read来传递数据,但write与read不可以同时进行,在管道中只能有4096字节的数据被缓冲。例5. 编写一个程序,建立一个pipe,同时父进程产生一个子进程,子进程向pipe中写入一个字符串,父进程从中读出该字符串,并每隔3秒种输出打印一次。main()int x,fd2;char S30;pipe(fd);for (;)x=fork();if (x=0)sprintf(S,”Good-night!n”);write(fd1,S,20);sleep(3);exit(0);elsewait(0);read(fd0,S,20);printf(“*n”,S); 实验题4. 编写一段程序,实现进程的管道通信。使用系统调用pipe()建立一条子管道线,2个子进程分别循环向这条管道写一句话:child1 is sending a message!Child2 is sending a message!而父进程则循环从管道中读出信息,显示在屏幕上。 返回 实验六 可变分区内存管理1基本思想可变分区是指系统不预先划分固定分区,而是在装入程序的时候划分内存区域,使得为程序分配的分区大小恰好等于该程序的需求量,且分区的个数是可变的。显然可变分区有较大的灵活性,较之固定分区能获得好的内存利用率。2数据结构可变分区管理可以用两种数据结构实现,一种是已分配区表和空闲区表,也就是用预先定义好的系统空间来存放空间分配信息。请参见教材P101页图4-10。另一种也是最常用的就是空闲链表,由于对分区的操作是动态的,所以很难估计数据结构所占用的空间,而且空闲区表会占用宝贵的系统空间,所以提出了空闲链表的概念。其特点是用于管理分区的信息动态生成并和该分区在物理地址上相邻。这样由于可以简单用两个空闲块之间的距离定位已分配空间,不仅节约了系统空间,而且不必维持已分配空间的信息,。下图是空闲链表的示意图。3实习要求请同学们实现一个完整的可变分区管理器,包括分配,回收,分区碎片整理等。希望同学们考虑如下问题:n 容错性,当操作出现错误,比如空间不足,空指针引用等的情况下的处理。n 空闲块的合并。n 已分配空间的跟踪。当做碎片整理时,需要跟踪分配的空间,修改其引用以保证引用的正确性。