ImageVerifierCode 换一换
格式:DOCX , 页数:38 ,大小:536.83KB ,
资源ID:7078011      下载积分:12 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/7078011.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(合操作系统实验指导书612.docx)为本站会员(b****6)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

合操作系统实验指导书612.docx

1、合操作系统实验指导书612操作系统实验指导书操作系统课程组编著计算机科学与技术系目 录前言 - 1 -实验项目一 熟悉LINUX基本命令及编程环境 - 2 -实验项目二 进程管理 - 4 -实验项目三 进程调度 - 9 -实验项目四 进程通信 - 15 -实验项目五 存储管理 - 24 -实验项目六 Shell程序设计 - 30 -前言操作系统是计算机本科各专业的专业核心课程,其实践性、应用性很强,实验教学环节是必不可少的一个重要环节。通过操作系统实验部分教学,使学生加深理解和更好的掌握操作系统的基本原理、技术和方法,巩固所学理论知识,激发实验兴趣,掌握实验要领,培养对操作系统理论课程所学知识

2、融会贯通和综合运用的能力。通过实验,使学生深入了解和熟练掌握Linux操作系统的使用,及在Linux操作系统下进行程序设计开发的方法,掌握操作系统中进程管理、进程调度、进程通信和存储管理的方法,使学生具有初步分析实际操作系统的能力,为今后学习使用其它的程序设计环境和语言打好基础。为了收到良好的实验效果,编写这本实验指导书。在指导书中,每一个实验均按照该课程实验大纲的要求编写,力求紧扣理论知识点、突出设计方法、明确设计思路,通过多种形式完成实验任务,最终引导学生有目的、有方向地完成实验任务,得出实验结果。实验前,指导教师布置实验任务,给定实验内容,进行一定的分析和讲解,学生进行预习,提前设计实验

3、方案,之后进入实验室进行实验;实验中,要求学生按照实验要求进行实验,认真完成每个实验项目的具体内容,指导教师全程指导协调实验进行,对于实验中学生所提问题进行具体解答;实验后,学生应当及时总结实验过程,并按照实际情况对实验报告进行填写,能对在实验过程中发生的问题及时分析并找到解决方案,提交实验报告;指导教师需要对实验报告进行认真批阅,并根据需要选取重点内容进行点评分析。实验项目一 熟悉LINUX基本命令及编程环境1、 实验类型本实验为验证性实验。2、 实验目的与任务1. 熟悉Linux操作系统的安装和使用;熟悉使用Linux字符界面,窗口系统的常用命令。2. 掌握运用Linux常用的编程工具;掌

4、握如何编辑、编译、运行程序。3、 实验准备1. 熟悉linux系统中常用命令及其功能2. 熟悉vi编辑器或Gedit编辑器的各项功能3. 复习C语言程序的编写。4、 实验内容1. 练习使用Gedit编辑器使用Gedit编辑器用C语言编写一个HelloWorld程序,并保存。具体操作:点击“任务栏位置主文件夹”,打开主文件夹位置文件浏览器,空白处右键单击,弹出菜单选择“创建文档空文件”,新建一个空文件,并命名为“hello.c”,右键单击“hello.c”,选择“使用Gedit打开”,在Gedit编辑器中编辑代码如下:#includeint main() printf(Hello,Wrold!n

5、);编辑完成后,点击“保存”,保存文件。#includevoid main() int x,y; printf(please input x:); scanf(%d,&x); if(x6) y = x - 12; printf(x = %d,y = %dn,x,y); else if(x15) y =3 * x - 1; printf(x = %d,y = %dn,x,y); else y = 5 * x + 9; printf(x = %d,y = %dn,x,y); 2. 使用gcc编译源程序。gcc是linux下的一种c程序编译工具,使用方法如下:编译: gcc -o filename1

6、 filename.c(或者gcc filename.c -o filename1),其中: filename.c是源文件名,filename1 是目标文件名,o代表object具体操作:点击“任务栏应用程序附件终端”,当前默认路径即为主文件夹,输入“gcc hello.c -o hello”,回车运行后,若无任何提示,怎说明编译成功,已生成可执行文件“hello“,若提示有错误,则根据具体提示回到Gedit中修改源程序,保存后重新编译.3. 执行程序执行:./filenamel 其中: filename1 是目标文件名。具体操作:在“终端”中输入“./hello”,回车后运行,若无错误,终端

7、中将显示运行结果“Hello,Wrold!”。5、 注意事项1. gcc编译器不能编译不带扩展名的c语言程序。2. 注意编译和运行程序的基本过程。3. 重新编辑源程序后,必须重新编译,才会生成新的可执行程序。实验项目二 进程管理1、 实验类型本实验为验证性实验。2、 实验目的1. 理解进程的概念,掌握父、子进程创建的方法。2. 认识和了解并发执行的实质,掌握进程的并发及同步操作。3、 实验预备知识1. fork()函数头文件:#include#include函数原型:pid_t fork(void);(pid_t 是一个宏定义,其实质是int,被定义在#include中)返回值: 若成功调用一

8、次则返回两个值,子进程返回0,父进程返回子进程ID;否则,出错返回-1函数说明:一个现有进程可以调用fork函数创建一个新进程。由fork创建的新进程被称为子进程(child process)。fork函数被调用一次但返回两次。两次返回的唯一区别是子进程中返回0值而父进程中返回子进程ID。子进程是父进程的副本,它将获得父进程数据空间、堆、栈等资源的副本。注意,子进程持有的是上述存储空间的“副本”,这意味着父子进程间不共享这些存储空间。linux将复制父进程的地址空间内容给子进程,因此,子进程有了独立的地址空间。为什么fork会返回两次?由于在复制时复制了父进程的堆栈段,所以两个进程都停留在fo

9、rk函数中,等待返回。因为fork函数会返回两次,一次是在父进程中返回,另一次是在子进程中返回,这两次的返回值是不一样的,过程如图2.1。调用fork之后,数据、堆栈有两份,代码仍然为一份但是这个代码段成为两个进程的共享代码段都从fork函数中返回,箭头表示各自的执行处。当父子进程有一个想要修改代码段时,两个进程真正分裂。图2.1 fork()函数分裂示意图示例代码:#include /对于此程序而言此头文件用不到#include#includeintmain(intargc,char* argv )intpid = fork();if(pid 0)printf(error!);elseif(

10、 pid = = 0 )printf(This is the child process!);else printf(This is the parent process! child process id = %d, pid);return0;fork函数的特点概括起来就是“调用一次,返回两次”,在父进程中调用一次,在父进程和子进程中各返回一次。fork的另一个特性是所有由父进程打开的描述符都被复制到子进程中。父、子进程中相同编号的文件描述符在内核中指向同一个file结构体,也就是说,file结构体的引用计数要增加。2. wait()函数头文件:#include#include函数原型:pi

11、d_t wait (int * status);返回值:如果执行成功则返回子进程识别码(PID),如果有错误发生则返回-1。函数说明:wait()会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果在调用wait()时子进程已经结束,则wait()会立即返回子进程结束状态值。子进程的结束状态值会由参数status 返回,而子进程的进程识别码也会一起返回。如果不在意结束状态值,则参数status 可以设成NULL。子进程的结束状态值请参考下面的waitpid()。示例代码:#include#include#include#includeint main(intargc,char* argv

12、)pid_t pid;int status,i;if(fork()= =0)printf(This is the child process .pid =%dn,getpid();exit(5);elsesleep(1);printf(This is the parent process ,wait for child.n);pid=wait(&status);i=WEXITSTATUS(status);printf(childs pid =%d .exit status=%dn,pid , i);3. waitpid()函数头文件:#include#include函数原型:pid_t wai

13、tpid(pid_t pid,int * status,int options);返回值:如果执行成功则返回子进程识别码(PID),如果有错误发生则返回-1。函数说明:waitpid()会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果在调用wait()时子进程已经结束,则wait()会立即返回子进程结束状态值。子进程的结束状态值会由参数status 返回,而子进程的进程识别码也会一快返回。如果不在意结束状态值,则参数status 可以设成NULL。参数pid 为欲等待的子进程识别码,其他数值意义如下:pid0 等待任何子进程识别码为pid 的子进程。参数option 可以为0 或下面

14、的组合:WNOHANG 如果没有任何已经结束的子进程则马上返回,不予以等待。WUNTRACED 如果子进程进入暂停执行情况则马上返回,但结束状态不予以理会。子进程的结束状态返回后存于status,底下有几个宏可判别结束情况:WIFEXITED(status)如果子进程正常结束则为非0 值。WEXITSTATUS(status)取得子进程exit()返回的结束代码,一般会先用WIFEXITED 来判断是否正常结束才能使用此宏。WIFSIGNALED(status)如果子进程是因为信号而结束则此宏值为真。WTERMSIG(status)取得子进程因信号而中止的信号代码,一般会先用WIFSIGNAL

15、ED 来判断后才使用此宏。WIFSTOPPED(status)如果子进程处于暂停执行情况则此宏值为真。一般只有使用WUNTRACED 时才会有此情况。WSTOPSIG(status)取得引发子进程暂停的信号代码,一般会先用WIFSTOPPED 来判断后才使用此宏。4. exit()函数头文件:#include函数原型:void exit(int status);返回值:无。函数说明:进程结束正常终止,返回结束状态。status为进程结束状态,是返回给父进程的一个整数,以备查考。为了及时回收进程所占用的资源并减少父进程的干预,UNIX/LINUX利用exit( )来实现进程的自我终止,通常父进程

16、在创建子进程时,应在进程的末尾安排一条exit( ),使子进程自我终止。exit(0)表示进程正常终止,exit(1)表示进程运行有错,异常终止。如果调用进程在执行exit( )时,其父进程正在等待它的终止,则父进程可立即得到其返回的整数。核心须为exit( )完成以下操作:(1)关闭软中断(2)回收资源(3)写记帐信息(4)置进程为“僵死状态”4、 实验内容1. 编写一C语言程序,实现在程序运行时通过系统调用fork( )创建两个子进程,使父、子三进程并发执行,父亲进程执行时屏幕显示“I am father”,儿子进程执行时屏幕显示“I am son”,女儿进程执行时屏幕显示“I am da

17、ughter”。#include #include#include#includeint main() int pid; printf(fork program starringn); pid = fork(); if(pid = 0) printf(sonn); else pid = fork(); if(pid =0) printf(daughtern); else printf(fathern); 2. 多次连续反复运行这个程序,观察屏幕显示结果的顺序,直至出现不一样的情况为止。记下这种情况,试简单分析其原因。3. 修改程序,在父、子进程中分别使用wait()、exit()等系统调用“实

18、现”其同步推进,并获取子进程的ID号及结束状态值。多次反复运行改进后的程序,观察并记录运行结果。5、 实验报告要求1. 列出实验内容1、3各程序清单,并以截图形式记录相应运行结果。2. 对实验运行结果进行分析:1)实验内容1运行结果为什么无固定顺序,fork()函数创建进程是如何并发执行的。2)实验内容3是如何实现父子进程的同步执行的。#include #include#includeint main()int n;char *message;int pid,status,i;printf(fork program starringn);pid = fork();if(pid = 0) mes

19、sage=son; n = 3; else pid = fork(); if(pid =0) message=daughter; n = 3; else message=father; n = 3;for(;n0;n-)puts(message);sleep(1); 实验项目三 进程调度1、 实验类型本实验为验证性实验。2、 实验目的1. 理解进程控制块和进程组织方式;2. 掌握时间片轮转调度算法实现处理机调度。3、 实验预备知识1. 实验基本原理进程控制块通过链表队列的方式组织起来,系统中存在运行队列和就绪队列(为简单起见,不设阻塞队列),进程的调度就是进程控制块在运行队列和就绪队列之间的切

20、换。当需要调度时,从就绪队列中挑选一个进程占用处理机,即从就绪队列中删除一个进程,插入到运行队列中,当占用处理机的进程运行的时间片完成后,放弃处理机,即在运行队列中的进程控制块经过一段时间(时间片)后,从该队列上删除,如果该进程运行完毕,则删除该进程(节点);否则,则插入到就绪队列中。2. 实验中使用的数据结构(1) PCB进程控制块内容包括参数进程名name;要求运行时间 runtime;已运行时间runedtime;本轮运行时间killtime。(2) 进程队列为简单起见,只设运行队列,就绪队列两种数据结构,进程的调度在这两个队列中切换,如图3.1所示。图3.1 PCB链表3. rand(

21、)函数和srand()函数库函数中系统提供了两个函数用于产生随机数:srand()和rand()。 函数一:int rand(void);从srand (seed)中指定的seed开始,返回一个0,RAND_MAX(0x7fff)间的随机整数。函数二:void srand(unsigned seed);参数seed是rand()的种子,用来初始化rand()的起始值。函数rand()是真正的随机数生成器,而srand()会设置供rand()使用的随机数种子。如果你在第一次调用rand()之前没有调用srand(),那么系统会为你自动调用srand()。而使用同种子相同的数调用 srand()会

22、导致相同的随机数序列被生成。srand(unsigned)time(NULL)则使用系统定时/计数器的值做为随机种子。每个种子对应一组根据算法预先生成的随机数,所以,在相同的平台环境下,不同时间产生的随机数会是不同的,相应的,若将srand(unsigned)time(NULL)改为srand(TP)(TP为任一常量),则无论何时运行、运行多少次得到的“随机数”都会是一组固定的序列,因此srand生成的随机数是伪随机数。但是,要注意的是所谓的“伪随机数”指的并不是假的随机数。其实绝对的随机数只是一种理想状态的随机数,计算机只能生成相对的随机数即伪随机数。计算机生 成的伪随机数既是随机的又是有规

23、律的一部份遵守一定的规律,一部份则不遵守任何规律。比如“世上没有两片形状完全相同的树叶”,这体现到了事物的特性差异性;但是每种树的叶子都有近似的形状,这正是事物的共性规律性。从这个角度讲,我们就可以接受这样的事实了:计算机只能产生伪随机数而不是绝对的随机数。系统在调用rand()之前都会自动调用srand(),如果用户在rand()之前曾调用过srand()给参数seed指定了一个值,那么 rand()就会将seed的值作为产生伪随机数的初始值;而如果用户在rand()前没有调用过srand(),那么系统默认将1作为伪随机数的初始值。如果给了一个定值,那么每次rand()产生的随机数序列都是一

24、样的。所以为了避免上述情况的发生我们通常用srand( (unsigned) time(0) )或者srand(unsigned)time(NULL)来 产生种子。如果仍然觉得时间间隔太小,可以在(unsigned)time(0)或者(unsigned)time(NULL)后面乘上某个合适的整数。 例如,srand(unsigned)time(NULL)*10)。另外,关于time_t time(0):time_t被定义为长整型,它返回从1970年1月1日零时零分零秒到目前为止所经过的时间,单位为秒。srand()、rand()用法举例:#include#includevoid main()

25、int i,j; srand(10); /srand(int)time(0); for (i=0; i10; i+) j = (int) (rand()%20; printf( %dn , j); 4. malloc()函数头文件:#include函数原型:void * malloc(unsigned int size);函数说明:其作用是在内存的动态存储区中分配一个长度为size的连续空间,此函数的值(即“返回值”)是一个指向分配域其实地址的指针(类型为void)。若此函数未能成功执行则返回空指针。5. 程序流程图图3.2模拟进程调度的流程图6. 部分参考程序(1) PCB数据结构struc

26、t PCB int name; int runtime;int runedtime; int killtime;struct PCB *next;typedef struct PCB PCB;(2) 创建就绪列表#define LEN sizeof(PCB)PCB *runqueue;/运行队列指针PCB *top,*tail,*temp;/就绪队列指针int i;srand(int)time(0);for(i=0;iname=i; temp-runtime=rand()%15; temp-runedtime=0; temp-next=NULL; temp-killtime=0; if(i=0

27、) top=temp; tail=temp; else tail-next=temp; tail=temp; printf(process name %d, runtime=%d, runedtime=%d,killtime=%dn, tail-name,tail-runtime,tail-runedtime,tail-killtime); 7. 按时间片轮转算法进行进程调度的过程描述。第1步:取就绪队列的队首结点为运行队列的结点,修改就绪队列队首指针后移;第2步:调度运行队列结点,即运行队列结点的要求运行时间减去时间片时间;第3步:a若修改后要求运行时间=0,则表示该进程结点运行完毕,修改进

28、程结点的PCB信息,记录runtime,runedtime,killtime等信息。并将结点信息输出。b否则,表示该进程结点未完成,记录runtime,runedtime,killtime等信息,将结点信息输出。并将该结点置于就绪队列的队尾,等待下次调度,同时修改队尾指针。第4步:若就绪队列非空,则继续执行第1步,直至就绪队列为空。4、 实验内容1. 建立合理的PCB数据结构,建立含有8个进程结点的就绪队列,每个进程的要求运行时间随机产生,要求每个进程的要求运行时间不大于15。2. 设置时间片大小(36),使用时间片轮转调度算法实现处理机调度。5、 实验报告要求1. 列出实验内容所要求的程序清单,并以截图形式记录相应运行结果;2. 对实验运行结果进行分析:如果时间片设置值过大或过小,会对进程的调度产生何种影响。实验项目四 进程通信1、 实验类型本实验为综合性实验。2、 实验目的1. 了解什么是消息,熟悉消息传送原理。2. 了解和熟悉共享存储机制。3. 掌握消息的发送与接收的实现方法。3、 实验预备知识任务一 消息的发送和接收1. 实验基本原理消息(message)是一个格式化的可变长的信息

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1