操作系统实验指导书完整版.docx
操作系统实验指导书绍兴文理学院计算机系1 .实验总体目的通过学生自己动手设计实验验证理论知识,使学生掌握操作系统特性和功能,掌握不同调度算法下进程的调度、进程控制、进程调度与死锁,并必须掌握作业管理、存储器管理、设备管理和文献管理的重要原理。加深对操作系统基本原理理解。2 .合用专业计算机科学与技术3 .先修课程C语言程序设计、计算机组成原理、数据结构4 .实验课时分派序号实验名称学时实验规定实验类型1分析操作系统所面临的操作需求2必修验证2进程管理4必修设计3存储管理4必修设计4设备管理2必修设计5文献管理4必修设计5 .实验环境有70台中档配置的计算机组成的小型局域网的实验室环境。计算机的具体规定:PentiUmI33Hz以上的CPU;建议至少256MB的内存;建议硬盘至少2GB,并有IGB空闲空间。安装Windows操作系统及C语言编译程序或1.inux虚拟环境。6 .实验总体规定培养计算机专业的学生的系统程序设计能力,是操作系统课程的一个非常重要的环节。通过操作系统上机实验,可以培养学生程序设计的方法和技巧,提高学生编制清楚、合理、可读性好的系统程序的能力,加深对操作系统课程的理解。使学生更好地掌握操作系统的基本概念、基本原理、及基本功能,具有分析实际操作系统、设计、构造和开发现代操作系统的基本能力。实验规定做到:1)具体描述实验设计思想、程序结构及各模块设计思绪;2)具体描述程序所用数据结构及算法;3)明确给出测试用例和实验结果;4)为增长程序可读性,在程序中进行适当注释说明;5)认真进行实验总结,涉及:设计中碰到的问题、解决方法与收获等;6)实验报告撰写规定结构清楚、描述准确逻辑性强;7)实验过程中,同学之间可以进行讨论互相提高,但绝对严禁抄袭。7.本实验的重点、难点及教学方法建议重点:理解进程调度中PCB的设计,以实现对进程的调度。难点:进程调度程序的设计,设备管理程序的设计。教学方法建议:力争在本指导书的帮助下,独立设计程序以加深理解。实验一分析操作系统所面临的操作需求(一)实验目的使学生理解操作系统所面临的操作需求,掌握操作系统中的进程管理、存储管理、设备管理和文献管理等功能。(二)实验内容1 .分析操作系统所面临的操作需求;2 .熟悉实验环境;3 .资料搜集与整理,进行实验的前期准备。熟悉编程环境本课程中的实验题目既可以在windows下用控制台应用程序实现,也可以在Iinux下用全屏幕程序实现。这里我们一方面介绍在windows下用vc6.0设计控制台应用程序的环节,然后介绍在Iinux下用C语言编写全屏幕程序的环节。1.WindOWS的控制台应用程序JaAJaSPueapv80z三*o<m程序唱MtyoiohutdMKyCeoftSCJClO6.0囱MUbthreDdrq超W苕宇图毛隽I启Microjoft-alseudo61为MrosoHKB-dEfasic6.0“MfcB3。FI,Cl6O运行国、口。君薄4S:,回团>-ai-A关M助(CS:25三*1行9列7和!卷受ZIJa3丫式岐I回计电机撵作姜更堂独图1-1图1-2U*cFlicsProjcctoWorkspacesOtherDocuments,Addturujecl:File1.ocation:回d±JActiveServerPeyeilRlnaryFlIeMHIImaPFileDQC*+HcadcrHIc场SQmGQ»CursorFileIiIM1.Page3IconFile;:MaCrOFile与ReSOIHCeScriptResourceTemplate国SQ1.ScriptHlcP)TextFile图1-3环节1:开机,单击“开始”按钮,选择“程序->MicrosoftVisualStudio6.0->MicrosoftVisualC+6.0”进入MicrosoftVisualC+6.0。见图I-Io环节2:在MiCroSoftViSUaIC+6.0中,单击“File”菜单,选择“New”菜单命令,见图1-2o环节3:在“Files”选项卡中选择“C+SourceFiIe”,见图132.Iinux的Vi应用编程登录1.inux是一个多用户多任务操作系统,多个用户可以拥有自己独立的用户账号登录提醒:RedHat1.inuxrelease6.0(Hedwing)Kernel2.2.5-15onani6861.ogin:此时输入用户户名(账号)并键入回车,则系统显示passward在输入密码和回车。登录后:roothawk/root#表达是按root方式登录S表达是普通用户。1.inUX大小写敏感,用“,加参数ZlinUX:#IS-FHowTo/HowlbMin/IinUXnag/sag/获取帮助:1.inUX带有联机手册,可以用man命令来阅读ZlinUX:$manIs虚拟终端1.inux可有多个用户登录到同一个计算机,但一般微机只有一个终端难以体现。可以使用多个虚拟终端,用Alt+Fl、Alt+F2等来切换。退出系统在停止使用系统时,要退出系统。具体方法:exit或IOgoUt,或Ctrl+D关机假如没有用户在使用系统,可以关机。但是不能直接关闭电源,而要按正常顺序关机。一般用户是不能关机的,只有root用户可以关机。方法:可以使用halt或ShUtdoWn命令,也可以同时键入CtrI+Alt+Del。Windows虚拟机环境:登录到系统点击桌面“VMware”图标>VmwareWorkstation窗口>Commands>Startthisvirtualmachine进入fedora后,用户名:root口令:123456使用编辑器Vi编辑文献1 .进入IinUX的文本模式之后,在命令行键入Vifilename.c然后回车。下面作一些简朴的解释:一方面Vi命令是打开Vi编辑器。后面的filename.c是用户即将编辑的C文献名字,注意扩展名字是c当然,Vi编辑器功能很强,可以用它来编辑其它格式的文献,比如汇编文献,其扩展名字是s也可以直接用Vi打开一个新的未命名的文献,当保存的时候再给它命名,只是这样做不很方便。2 .最基本的命令I:当进入刚打开的文献时,不能写入信息,这时按一下键盘上的I键(insert),插入的意思,就可以进入编辑模式了。如下图所示:11in()1抵入2.26-33全部3 .a与i是相同的用法4 .当文献编辑完后,需要保存退出,这时需要通过以下几个环节:1)按一下键盘上的Esc键;2)键入冒号(:),紧跟在冒号后面是Wq(意思是保存并退出)。假如不想保存退出,则在第二步键入冒号之后,键入!q(不带w,机尾部保存)。如下图所示:11in()(PrinQlnmIOwrId!w):I5 .退出Vi编辑器的编辑模式之后,要对刚才编写的程序进行编译。编译的命令是:gccfilename.c-ooutputfilename,其中gcc是C的编译器。参数:filename.c是刚才编辑的C文献(当然也可以是以前编写好的C文献);后面中括号里面的参数是可选的,它是一个输出文献。假如不选,默认的输出文献是a.out,选了之后输出文献就是OUtputfiIename-OUt.6 .最后一步是运营程序,方法如下:.oJtPUtfiIename.out实验二进程管理(一)实验目的掌握临界区的概念及临界区的设计原则;掌握信号量的概念、PV操作的含义以及应用PV操作实现进程的同步与互斥;分析进程争用资源的现象,学习解决进程互斥的方法;掌握进程的状态及状态转换;掌握常用的进程调度算法。(二)实验内容1 .分析进程的同步与互斥现象,编程实现经典的进程同步问题一一生产者消费者问题的模拟;2 .编写允许进程并行执行的进程调度程序,在常用的进程(作业)调度算法:先来先服务算法、短作业优先算法、最高响应比优先算法、高优先权优先算法等调度算法中至少选择三种调度算法进行模拟,并输出平均周转时间和平均带权周转时间。本实验涉及内容较多,可以在两个题目里选择一个完毕。编程实现经典的进程同步问题生产者消费者问题的模拟模拟实现用同步机构避免发生进程执行时也许出现的与时间有关的错误。进程是程序在一个数据集合上运营的过程,进程是并发执行的,也即系统中的多个进程轮流地占用解决器运营。我们把若干个进程都能进行访问和修改的那些变量称为公共变量。由于进程是并发地执行的,所以,假如对进程访问公共变量不加限制,那么就会产生“与时间有关”的错误,即进程执行后所得到的结果与访问公共变量的时间有关。为了防止这类错误,系统必须要用同步机构来控制进程对公共变量的访问。一般说,同步机构是由若干条原语一一同步原语一所组成。本实验规定模拟PV操作同步机构的实现,模拟进程的并发执行,r解进程并发执行时同步机构的作用。本次用到的数据结构知识如下:typedefstructPcbcharname10;charstate10;charreason10;intbreakp;structPcb*ne×t;Pcb,*link;进程名运营状态若阻塞,其因素断点保护阻塞时的顺序进程名状态等待因素断点后继进程进程控制块结构定义两个进程:linkpl;生产者进程,linkcl;消费者进程。PC程序计数器和linkready;就绪队列,linkb_sl;Sl阻塞队列,linkb_s2;s2阻塞队列。实验指导:a.h头文献#include<string.h>#include<ctype.h>#include<malloc.h>/*malloc()等*/#include<limits.h>*INT_MAX等*/include<stdio.h>*EOF(=Z或F6)zN1.1.*/ftinclude<stdlib.h>*atoi()*/ttinclude<io.h>*eof()*/#include<math.h>/*floor()zceil()zabs()*/#include<process.h>*e×it()*/#include<iostream>usingnamespacestd;#include<time.h>#defineBUF10缓存的大小#defineMAX20最大可以输入的字符b.h头文献数据结构的定义和全局变量typedefstructPcbcharname10;进程名charstate10;运营状态charreason10;若阻塞,其因素intbreakp;断点保护structPcb*next;阻塞时的顺序Pcb,*link;intsl,s2;信号量linkpl;生产者进程IinkC1;消费者进程charstrMAX;输入的字符串charbufferBUF;缓冲池inten;输入长度intsp=O;/string的指针intin=O;生产者指针intout=0;消费者指针Chartemp;供打印的临时产品CharrejpMAX;生产记录intrpl=O;生产记录指针CharrejcMAX;消费记录intrp2=0;消费记录指针Iinkready;就绪队列Iinkb_sl;SI阻塞队列linkb_s2;/s2阻塞队列intpc;程序计数器intcount;字符计数器intCOn_cnt;消费计数器h头文献voidinit();初始化voidp(ints);/P操作voidv(ints);/V操作voidblock(ints);阻塞函数voidwakeup(ints);唤醒函数voidcontrol();解决机调度voidpr。CeSSOr();解决机执行voidprint();打印函数voidinit()初始化Sl=BUF;s2=0;Pl=(Iink)malloc(sizeof(Pcb);建立新的结点,并初始化为生产者strcpy(pl->name'Producer");strcpy(pl->state,Ready");strcpy(pl->reason'Null");pl->breakp=O;pl->ne×t=NU1.1.;CI=(Iink)malloc(sizeof(Pcb);建立新的结点,并初始化为消费者strcpy(cl->name'Consumer");strcpy(cl->statez"Ready");strcpy(cl->reason,"Null");cl->breakp=O;cl->ne×t=NU1.1.;ready=pl;ready->next=cl;初始化为生产进程在前,消费进程在后cl->next=NU1.1.;b_sl=NU1.1.;b_s2=NU1.1.;阻塞进程为NU1.1.pc=O;Con_cnt=O;消费计数器)voidp(ints)if(s=l)/p(sl)sl-;if(sl<O)block(l);阻塞当前生产进程elserintf(,t*Sl信号申请成功!n");ready->breakp=pc;保存断点)else(p(s2)s2-;if(s2<0)block(2);阻塞当前消费进程else(printf(,t*s2信号申请成功!n”);ready->breakp=pc;保存断点voidv(ints)if(s=l)v(sl)si+;if(sl<=O)WakeUP(1);唤醒生产进程ready->breakp=pc;保存断点else/v(s2)s2+;if(s2<=O)WakeUP(2);唤醒消费进程ready->breakp=pc;保存断点)voidblock(ints)阻塞函数的定义linkp;intnuml=0;intnum2=0;if(s=l)/生产进程StrCPy(Pl->stateJBIock");改变状态StrCPy(PI->reasonJSl");说明因素P=b_sl;while(p)numl+;p=p->nextp的值为NU1.1.,表达队尾)if(!b_sl)b_sl=pl;elsep=pi;pl->next=NU1.1.;printf("t*pl生产进程阻塞了!n”);ready->breakp=pc;保存断点ready=ready->next;在就绪队列中去掉,指向下一个numl+;)ese消费进程strcpy(cl->statez"Block");strcpy(cl->reason,"S2");P=b_s2;while(p)num2+;p=p->nextp的值为NU1.1.,表达队尾if(b.s2)b_s2=cl;elseP=cl;ready->breakp=pc;保存断点ready=ready->next;在就绪队列中去掉,指向下一个cl->next=NU1.1.;printf("t*cl消费进程阻塞了ln“);num2+;)printf(,t*阻塞的生产进程个数为:dnnuml);printf("t*阻塞的消费进程个数为:dn”,num2);)voidwakeup(ints)唤醒函数的定义linkp;linkq=ready;if(s=l)唤醒b_sl队首进程,生产进程队列P=b_sl;b_sl=b_sl->next;阻塞指针指向下一个阻塞进程strcpy(p->state,"Ready");strcpy(p->reasonz"Null");WhiIe(q)插入就绪队列q=q->next;q=P;p->next=NU1.1.;printf(11t*pl生产进程唤醒了!n");)else唤醒b_s2队首进程,消费进程队列P=b_s2;b_s2=b_s2->next;阻塞指针指向下一个阻塞进程strcpy(p->statez"Ready");strcpy(p->reason,"Null");WhiIe(q->next)插入就绪队列q=q->next;q->next=p;p->next=NU1.1.;printf("t*Cl消费进程唤醒了!n");)voidcontrol。解决器调度程序(intrd;intnum=O;linkp=ready;if(ready=NU1.1.)若无就绪进程,结束return;Whiie(P)记录就绪进程个数num+;p=p->next;最终p变为NU1.1.)printf(,t*就绪进程个数为:dn",num);time_tt;srand(unsigned)time(&t);rd=rand()%num;随机函数产生随机数if(rd=l)p=ready;ready=ready->next;ready->next=p;p->next=NU1.1.;strcpy(ready->statez"Run");strcpy(ready->next->state'Ready");)elsestrcpy(ready->statez"Run");pc=ready->breakp;voidProCeSSor()模拟解决器指令执行if(strcmp(ready->name,"Producer")=。)当前进程为生产者switch(pc)(caseOproduceprintf(,t*生产者生产了字符cn",strsp);rejprpl=strsp;添加到生产记录sp=(sp+l)%len;pc+;ready->breakp=pc;保存断点break;case 1: /p(sl)pc+;Pd);break;case 2: /putbufferin=reJPTP1;放到缓冲区printf("t*%c字符成功入驻空缓存!n,bufferin);rpl+;in=(in+l)%BF;pc+;ready->breakp=pc;保存断点break;case 3: /v(s2)pc+;printf(',t*释放一个s2信号r);v(2);break;case4goto01printf("t*生产进程goto。操作n“);pc=0;COUnt-剩余字符个数减1printf("t*剩余字符count=%d个n”,count);ready->breakp=pc;保存断点if(count<=0)生产结束printf("t*生产者结束生产ln”);strcpy(pl->state,Stop");strcpy(pl->reason,"Null");ready->breakp=-l;ready=ready->next;在就绪队列中去掉)else当前进程为消费者switch(pc)caseO:/p(s2)pc+;P(2);break;case 1: /getprintf("t*消费者取字符!rf);temp=bufferout;out=(out+l)%BUF;pc+;ready->breakp=pc;保存断点break;case 2: /v(sl)pc+;printf(11t*释放一个sln");v(l);break;case 3: /consumePrintf("t*消费了字符cn",temp);rejcrp2=temp;添加到消费记录rp2+;con_cnt+;if(con_cnt>=len)StrCPy(CI->state,"Stop");完毕态cl->breakp=-l;return;pc+;ready->breakp=pc;保存断点break;case 4: /gotoOPrintf(',t*消费进程goto。操作n");pc=0;ready->breakp=pc;保存断点)voidprint()iti,j;printf("生产者消费者模拟n");printf("*模拟过程的字符串为:t");printf(',%sn"str);printf("*己生产:");for(j=0;j<=rpl;j+)printf("%c"jrec-pj);printf("n*空缓存巧;for(j=rp2;j<=rpl;j+)printf("%c",bufferj);printf("n*己消费:”);for(j=0;j<=rp2;j+)printf(',%c",rec-cj);printf("n进程控制块的信息-n");Printf("进程名tt状态t等待因素t断点n");printf(,%st%st%stt%dnn",pl->name,pl->state,pl->reasonzpl->breakp);printf("%st%st%stt%dn",cl->name,cl->statezcl->reason,cl->breakp);printf("An");Printf(”1.继续0.退出n“);scanf("%d',i);if(i=0)exit(0);)主程序#include,a.h"include"b.h"include"c.h"voidmain()Printf("生产者消费者模拟n“);printf("n");Printf(”*请输入字符串:n”);scanf("%s"zstr);String数组存放将要产生的字符Ien=StrIenfstr);count=len;输入字符的个数init();初始化WhiIe(COnnt<len)消费完所有的字符为结束(system("cls");清屏操作printf("模拟指令流程n");control);解决器调度程序processor!);模拟解决器指令执行print();输出显示各个信息printf("n程序结束!n”);进程调度算法模拟进程管理是操作系统中的重要功能,用来创建进程、撤消进程、实现进程状态转换,它提供了在可运营的进程之间复用CPU的方法。在进程管理中,进程调度是核心,由于在采用多道程序设计的系统中,往往有若干个进程同时处在就绪状态,当就绪进程个数大于解决器数目时,就必须依照某种策略决定哪些进程优先占用解决器。本实验模拟在单解决器情况下的进程调度,目的是加深对进程调度工作的理解,掌握不同调度算法的优缺陷。设计一个按先来先服务、时间片轮转法、优先数调度算法实现解决器调度的程序。实验指导:#include<stdio.h>#include<stdlib.h>#include<string.h>include<conio.h>typedefstructnode(charname10;*进程标记符*/intprio;*进程优先数*/intround;/*进程时间轮转时间片*/intCputime;/*进程占用CPU时间*/intneedtime;/*进程到完毕还要的时间*/intarrivetime;/*进程到达时间*/intstarttime;/*进程开始时间*/intfinishtime;*进程完毕时间*/intservicetime;/*进程服务时间*/floatturnaroundtime;/*进程周转时间*/floatweightedturnaroundtime;/*进程带权周转时间*/intcount;/*计数器*/charstate;/*进程的状态*/structnode*next;/*链指针*/PCB;PCB*finish,*read½*tail,*run;/*队列指针*/intN;/*进程数*/*将就绪队列中的第一个进程投入运营*/voidfirstin()(run=ready;/*就绪队列头指针赋值给运营头指针*/run->state='R'/*进程状态变为运营态*/ready=ready->next;/*就绪对列头指针后移到下一进程*/)/*标题输出函数*/voidprtl(chara)(switch(八)状态Printf("名字进程占用CPU时间进程到完毕还要的时间优先级数n");break;case 2: /*时间片算法*/Printf("名字进程占用CPU时间进程到完毕还要的时间计数器时间片状态n");break;case 3: /*先来先服务算法*/Printf("名字到达时间开始时间服务时间完毕时间周转时间带权周转时间状态n");break;default:break;)/*进程pCB输出*/voidprt2(chara,PCB*q)(switch(八)(case1:*优先数法的输出*/printf(,%-10st%-10dt%-10dt%-10dt%cn,q->name,q->cputimezq->needtime,q->prio,q->state)jbreak;case2:/*轮转法的输出*/printf(,%-10s%-20d%-15d%-10d%-10d%-cn,q->namezq->cputimezq->needtime,q->count,q->round,q->state)jbreak;printf("%s%10d%10d%10d%10d%10.1f%10.2tt%cn",q->name,q->arrivetimezq->starttime,q->servicetime,q->finishtimezq->turnaroundtime,q->weightedturnaroundtimezq->state);break;default:break;)/*输出函数*三7voidprt(charalgo)(PCB*p;prtl(algo);*输出标题a7if(run!=NU1.1.)*假如运营指针不空*/prt2(algo,run);/*输出当前正在运营的PCB*/p=ready;/*输出就绪队列PCB*/while(p!=NU1.1.)(prt2(algo,p);p=p->next;)p=finish;/*输出完毕队列的PCB*/while(p!=NU1.1.)prt2(algo,p);p=p->next;getch();/*压任意键继续*/)/*优先数的插入算法*/voidinsertl(PCB*q)(PCB*plz*sr;intb;s=q;/*待插入的PCB指针*/pl=ready;/*就绪队列头指针*/r=pl;/*r做pl的前驱指针*/b=l;WhiIe(P1!=NU1.1.)&&b)/*根据优先数拟定插入位置*/if(pl->prio>=s->prio)r=pl;pl=pl->next;)elseb=0;if(r!=pl)/*假如条件成立说明插入在r与Pl之间*/r->next=s;s->ne×t=pl;elses->next=pl;*否则插入在就绪队列的头*/ready=s;)/*轮转法插入函数*/voidinsert2(PCB*p2)(tail->next=p2;/*将新的PCB插入在当前就绪队列的尾*/tail=p2;p2->next=NU1.1.;)/*先来先服务插入函数*/voidinsert3(PCB*q)(PCB*plz*sr;intb;s=q;/*指针S指向新要插入的进程*/pl=ready;/*指针Pl指向本来的进程的对首*/r=pl;/*使用指针r指向Pl前面的进程*/b=l;While(P1!=NU1.1.)&&b)if(pl->arrivetime<s->arrivetime)(r=pl;pl=pl->next;)elseb=0;if(r!=pl)(r->next=s;s->ne×t=pl;)else(s->ne×t=pl;ready=s;)/*优先数创建初始PCB信息*/voidcreatel(charalg)PCB*p;inti,time;charna10;ready=NU1.1.;*就绪队列头指针*/finish=N1.1.;/*完毕队列头指针*/run=N1.1.;/*运营队列头指针*/Printf("请输入进程的名字和运营所需要的时间己);/*输入进程标记和所需时间创建PCB*/for(i=l;i<=N;i+)(p=(PCB*)malloc(sizeof(PCB);scanf("%s',zna);scanf(',%d"time);strcpy(p->namezna);p->cputime=O;p->needtime=time;p->state='W,;p->prio=50-time;if(ready!=NU1.1.)/*就绪队歹IJ不空则调用插入函数插入*/insertl(p);elsep->next=ready;/*创建就绪队列的第一个PCB*/ready=p;)voidclrscr(void);printf("优先级调度算法模拟输出结果:n");printf("*prt(alg);/*输出进程PCB信息*/run=ready;/*将就绪队列的第一个进程投入运营*/ready=ready->next;run->state='R")/*轮转法创建进程PCB*/voidcreate2(charalg)(PCB*p;inti,time;charna10;ready=NU1.1.;finish=NU1.1.;run=NU1.1.;Printf("请输入进程的名字和运营所需要的时间n“);for(i=l;i<=N;i+)(p=(PCB*)malloc(sizeof(PCB);scanf(,%s",na);scanf(,%d"time);strcpy(p->namezna);p->cputime=O;p->needtime=time;p->count=0;/*计数器*/p->state='W'p->round=2;/*时间片*/if(ready!=NU1.1.)insert2(p);else(p->next=ready;ready=p;tail=p;)voidclrscr(void);printf("时间片轮转法模拟输出结果:n");"*木*木*n");prt(alg);/*输出进程PCB信息*/run=ready;/*将就绪队列的第一个进程投入运营*/ready=ready->ne×t;run->state='R,;)/*先来先服务算法创建PCB*/voidcreate3(charalg)(PCB*p;inti;ready=NU1.1.;run=NU1.1.;finish=NU1.1.;Printf(U请输入进程的名字、到达时间和运营所需要的时间n”);for(i=0;i<N;i+)(p=(PCB*)malloc(sizeof(PCB);scanf("%s,p->name);scanf("%d"p->arrivetime);scanf("%d"p->servicetime);p->starttime=O;p->finishtime=O;p->turnaroundtime=0;p->weightedturnaroundtime=O;p->state='W'if(ready!=NU1.1.)insert3(p);else(p->ne×t=ready;ready=p;)voidclrscr(void);printf("先来先服务算法模拟输出结果:n");printf(,1*n");prt(ag);run=ready;/*将就绪队列的第个进程投入运营*/ready=ready->ne×t;run->s