操作系统课程设计 报告.doc
操作系统程序设计操作系统模拟实现 院 系: 计算机科学技术学院软件工程系 班 级: 软件 08 1 班 姓 名: X X X 学 号: X 号 指导教师: X X X 2010 年6月 26日操作系统程序设计任务书一、题目:操作系统模拟实现二、设计要求(1)独立完成(2)良好的交流、沟通能力(3)充分运用前序课所学的软件工程、程序设计等相关知识(4)充分运用调试和排错技术(5)简单测试驱动模块和桩模块的编写 (6)查阅相关资料,自学具体课题中涉及到的新知识。(7)按要求写出课程设计报告,并于设计结束后1周内提交。其主要内容包括:封皮、课程设计任务书,指导教师评语与成绩、目录、概述、软件需求分析、总体设计、详细设计、程序的调试与测试、总结与体会、结束语、程序清单(带中文注释)、参考文献等。三、设计内容及步骤1.根据设计题目的要求,充分地分析和理解问题,明确问题要求做什么。具体要求至少实现进程管理模拟、存储器管理模拟、文件管理模拟,并将几个模块较好地集成一个整体,给出一个较好的用户界面。2.根据实现的功能,划分出合理的模块,明确模块间的关系。3.编程实现所设计的模块。4.程序调试与测试。5.结果分析。程序运行结果包括正确的输入及其输出结果和含有错误的输入及其输出结果。6.编写课程设计报告;四、课程设计工作计划2010年6月12日前,指导教师讲课,学生根据题目准备资料,需求分析;2010年6月13日,提交软件总体模块结构图和分工方案;2010年6月13日2009年6月16日,完成程序模块并通过独立编译;2010年6月17日2010年6月20日,将各模块集成为一个完整的系统,并录入足够的数据进行调试运行,数据必须存储到磁盘文件中,已备验收;2010年6月22日,验收、开始撰写课程设计报告;2010年6月24日前,提交课程设计报告,并将软件的源文件及报告的word文档打印交到老师办公室里。 指导教师签章: 教研室主任签章 操作系统导教师评语与成绩指导教师评语:课程设计表现成绩: 课程设计验收成绩: 课程设计报告成绩: 课程设计 总成绩: 指导教师签章 2010年 7月 日目 录目 录I一、需求分析11.1 功能需求11.2 背景描述11.3 具体设计内容分析1二、总体概要设计32.1 系统的特点32.2抽象数据整合32.3系统模块图5三、详细设计63.1基本操作63.2进程调度之时间片轮转详细设计73.3 模拟文件-改变目录流程10四、程序的调试与测试134.1调试分析134.2 测试结果14五、用户使用说明19六、总结与体会20参考文献21附录:程序清单22一、需求分析1.1 功能需求操作系统原理课程设计是软件工程专业实践性环节之一,是学习完操作系统原理课程后进行的一次较全面的综合练习。其目的在于加深对操作系统的理论、方法和基础知识的理解,掌握操作系统结构、实现机理和各种典型算法,进程调度、内存管理、文件管理、等各种调度管理算法模拟,系统地了解操作系统的设计和实现思路,培养学生的系统设计能力,并了解操作系统的发展动向和趋势。1.2 背景描述经过一个学期的操作系统原理、操作系统实验教程课程的学习,我们学到了很多理论上的知识,对操作系统及其各方面的功能有了深刻的认识,但这是远远不够的,我们要讲理论编程实践,虽然我们学习期间做过很多的实验,但是都是针对操作系统的某一块具体的功能的,我们对了解了每块具体的功能的实现,但是,整体说来还是模糊,所以,很有必要将各个模块整合起来,也就是模拟一个操作系统,这样,不仅跟深入学习了各个模块,更认识了一个完整的OS,对我们来说受益匪。1.3 具体设计内容分析 本次课程设计所用环境:VC+6.0,采用控制台界面至少实现进程管理模拟、存储器管理模拟、文件管理模拟,并将几个模块较好地集成一个整体,实现各个管理调度算法的功能,并给出一个较好的用户界面。进程管理模拟:在多道程序运行环境下,进程数目一般多于处理机数目,是的进程要通过竞争来使用处理机。这就要求系统能按某种属案发,动态的把处理机分配给就绪队列中的一个进程,使之运行。进程调度包括常用的:先来先服务、时间片轮转、优先权等因为以前已经实现,所以这次 模拟整合到一起不算很难。存储器管理模拟:主存是中央处理器直接存取指令和数据的存储器,能否合理的利用主存,在很大程度上将影响到整个计算机系统的性能。在多道作业和多进程环境下,共享主存空间。当作业执行完毕或进程运行结束后将主存空间归还系统。这次模拟包括:贮存分配与回收、基于分页的内存调度算法。有于模拟的比较简单,仅实现了最先适应算法、和先来先服务、最近你最久未使用的调度算法,实现比较简单。文件管理模拟:用于用户界面和操作命令在操作系统中的作用,实现操作系统中对文件的管理。文件中建立一个双向链表,每个聊表节点又是单链表的头结点,对目录、文件操作比较简单。 二、总体概要设计2.1 系统的特点本次可设主要是简单的模拟一个操作系统,包括一个主界面,实现了银行家算法、模拟文件管理、主存空间的分配与回收、进程调度等功能。模拟了操作系统的进程管理、文件管理、存储器管理。银行家算法,包括了新加作业、申请资源、撤销作业、查看资源情况四个模块。如果申请资源后系统进入不安全状态,则申请失败。进程调度实现了调度进程的三个主要算法优先数、先来先服务、时间片轮转法。其中,优先数算法中优先数的确定为(50-进程的服务时间),每轮一次优先数-3。时间片轮转法的时间片由用户自己输入。存储器管理实现了申请空间、撤销作业、显示空闲表等功能。如果空闲空间不足则申请失败。模拟文件管理很全面,包含了创建目录、删除目录、改变目录、创建文件、删除文件、显示目录的功能。另外,我还加了回到根目录的功能。2.2抽象数据整合银行家算法:const int MAX_P=20; / 进程的最大容量const int MAXA=10; / A类资源的最大数量const int MAXB=5; /B类资源的最大数量const int MAXC=7; /C类资源的最大数量typedef struct anode int a,b,c,/*三种资源总数*/remain_a,remain_b,remain_c/*三种资源剩余数*/; bank;typedef struct node1 char name20; int a,b,c,need_a,need_b,need_c; process; / 进程的结构体结点模拟文件管:typedef struct bnode char name50; int type;/*0代表目录,1代表普通文件*/ struct bnode *next,/* 兄弟节点*/*sub,/*第一个子节点*/*father/*父节点*/; int size; /*文件的大小*/dirnode;dirnode *workdir;/当前工作目录 dirnode root;/根目录 char path100;/定义路径信息 const int MAXJOB = 100;/定义最大记录数存储器管理:首先需要建立空闲区数据文件,空闲区数据文件包括若干行,每行有两个字段:起始地址,内存块大小(均为整数),各自段一逗号隔开。空闲区数据文件:0,1010,0818,1028,0634,1044,09空闲表的结构:typedef struct cnodeint start;int length;char tag20;job; job freesMAXJOB;/定义空闲区表 int free_quantity;job occupysMAXJOB;int occupy_quantity;进程调度:进程存在的标识是进程控制块(PCB),进程控制块结构如下:typedef struct dnode char name10; int prio; int round; int cputime; int needtime; int count; char state; struct dnode *next;PCB; / 进程的PCBPCB *finish,*ready,*run,*r;2.3系统模块图申请资源申请资源申请资源进程调度存储器管理模拟文件管理主界面新加作业银行家算法申请资源撤销资源申请资源优先数调度时间片轮转先来先服务申请空间撤销作业显示空闲表改变目录创建目录创建文件删除文件显示目录图 1 系统模块图三、详细设计3.1基本操作1)银行家算法:银行家算法主要由5个函数实现了四大功能,即新加作业、为作业申请资源、撤销作业、查看资源情况。void yinitial() /初始化函数void add() / 新加作业函数void bid() /为作业申请资源void yfinished()/撤销作业void yview()/查看资源情况2)模拟文件管理:模拟文件管理实现了很多功能,当然也有很多函数,每一个文件和目录都是用一个节点来描述的,用type来控制,有两个值,0和1,0代表目录,1代表普通文件void minitial() /初始化目录函数dirnode * init() /初始化新节点的函数void CD(char dirname) /改变目录void CREATE(char filename,int filesize) /创建文件void DEL(char filename)/删除文件void dir(dirnode *p) /现实所有目录,本目录下所有兄弟目录和文件void dirs(dirnode *p,char str)/显示由目录下子目录中的文件和目录void LSALL()/显示所有目录void MD(char dirname)/创建目录void RD(char dirname)/删除目录3)存储器管理:void initial()/初始化函数int readData()/读数据函数void sort()/将空闲块按照从小到大的顺序排序void zview()/显示函数void earlist()/最先适应分配算法void zfinished()/撤销作业4)进程调度:void firstin()/调度进程使之运行void prt1(char a)/*void prt2(char a ,PCB *q)void prt(char algo)*/上面的三本分主要是显示出来进程的调度情况void insert1(PCB *q)/插入新的进程void creat1(char alg)/*void creat2(char alg)*/以上两个实现进程的创建void priority(char alg)/优先数算法的实现void roundrun(char alg)/时间片轮转法的实现void FCFSrun(char alg)/先来先服务算法的实现void xianshi()/显示主界面的函数void yinhangjia()/主函数掉该函数实现银行家算法void wenjianguanli()/主函数调度该函数实现文件管理void zhucunkongjian()/主函数调度该函数实现存储器管理void jinchengdiaodu()/主函数调度该函数实现进程调度3.2进程调度之时间片轮转详细设计进程调度中对于先来先服务调度原理简单、实现也很简单、对于优先数调度来讲,每次调度的就是优先权最高的,所以每次只要找到优先权最高的就能实现,用到2个单链表:一个等待服务、一个连接完成。在这里就不多说了。对于时间片轮转,可以设定时间片大小、中途不能改变,我就建立一个循环链表来存放等待进程,一个单链表来连接完成的进程。这个实现的时候,费了不少劲儿,但最终能没有bug的显示出来。这个调度有一个缺陷:要求进程必须是同时到达,由于时间仓促,我就没设计这个内容。如果涉及的话,我感觉能整出来无非是多加个标记,标签来判断进程的到达及服务。忘了说了,对于时间片算法,进程我是按顺序进行插入的。主要核心代码:void creat2(char alg) PCB *p; int i,time,round; char na10; ready = NULL; finish = NULL; run = NULL; printf("请输入时间片:"); scanf("%d",&round); printf("输入进程号和运行时间:n"); for(i = 1; i <= N; i+) p = (PCB *)malloc(sizeof(PCB); scanf("%s",na); scanf("%d",&time); strcpy(p->name,na); p->cputime = 0; p->needtime = time; p->state = 'W' p->count = 0; p->round = round; p->next = NULL; if(i = 1)/*按顺序插入到ready链表中*/ r = ready = p; else r->next = p; r = p; /clrscr(); printf(" 时间片轮转算法输出信息:n"); printf("*n"); prt(alg);void roundrun(char alg)bool flag;/当ready列里只有一个时做标记 while(N) flag = 1;/初始化为1 run = ready;/run每次运行ready的队头 run->count+;/没运行一次计数器加1 if(run->needtime < run->round)/当剩余时间小于时间片轮转时间时的情况 run->cputime += run->needtime; run->needtime = 0; else run->cputime += run->round; run->needtime -= run->round; run->state = 'W'/变为等待 if(ready->next != NULL) ready = ready->next; else flag = 0;/当ready剩一个时做标记 if(run->needtime = 0)/当run结束时放入finish队列里 run->next = finish; finish = run; run->state = 'F' N-;/进程数少1 else if(flag)/执行完如果不是剩一个的话,就把run放到队尾 r->next = run; r = run; r->next = NULL; if(N)ready->state = 'R'/结束时不应该有'R" else ready = NULL;/结束时应该为空 prt(alg);/输出 截图显示:图 A、B、C。图A 时间片轮转算法界面图B 时间片轮转算法开始图C 时间片轮转运行结束3.3 模拟文件-改变目录流程由于模拟文件管理采用双向链表,可以来回搜索。进入子目录后还可以回到根目录,所以就在程序加了返回到上一级目录的功能,就是在CD()函数里加个条件,控制回到子目录还是上级目录。主要代码:void CD(char dirname) dirnode *p; int flag=0; if(strcmp(dirname,".") p=workdir->sub; if(p=NULL) cout<<"错误,""<<dirname<<""子目录不存在"<<endl; else while(p) if(p->type=0) if(!strcmp(p->name ,dirname) flag=1; break; p=p->next; if(flag=1) workdir=p; strcat(path,""); strcat(path,p->name); cout<<"工作目录已进入""<<dirname<<"""<<endl; else cout<<"错误,""<<dirname<<""子目录不存在"<<endl; else if(strcmp(workdir->name,"root") workdir = workdir->father; for(int i = strlen(path)-1; i >= 0; i-) if(pathi ='') pathi = '0'break; cout<<"工作目录已进入""<<path<<"""<<endl; else cout<<"错误,"<<"当前已是根目录"<<endl; 模块流程图:如图所示开始传入diranme,*pdirname!=”.”dirname!=root输出上级目录p = workdir->subP!=nulllp = p->next进入子目录子目录不存在已是根目录结束NYYNNY图2 改变目录流程四、程序的调试与测试4.1调试分析(1)在试验过程中遇到了很多错误,最开始的时候,在将各个模块连接起来的时候几个函数的名字一样,出现了错误,如图:图 3错误显示后来将函数的名字都改变了一下。(2)在主函数中将各个模块的主函数连起来的时候,退出来的时候整个程序就结束了,而我是想推出来的时候是退回到主界面,后来又给改了一下,加了一个while循环,还有变量flag,有flag来控制,当flag=0的时候就跳出while循环,然后清屏,掉一个编好的显示函数,显示主界面,这样就退回了主界面,后来又发现主函数有很多东西,很乱,我又将每个模块的主函数部分又分出去一个函数,这样主函数掉每个模块的原来的主函数部分就好了。(3)在内存调度算法中由于windows里面没有getpid()函数不了解rand()就用结果造成却也计算率也来小。如图:图 4 内存调度算法FIFO中无getpid()错误4.2 测试结果可设主界面:如图 图 5 设计主界面银行家算法:图 6 银行界算法主界面新加作业:图7 添加作业查看资源情况:图 8 资源使用情况为作业申请资源:图9 申请资源撤销作业:图10 撤销作业模拟文件管理:如图创建目录:图 11 模拟文件管理界面改变目录:图12 改变目录回到上一级目录:图13 返回上一级目录显示目录:图14 显示所有目录存储器管理模拟:如图显示空闲表:图15 显示空闲区分配表申请空间:图 16 申请空间进程调度模拟:优先数算法:图17 优先数算法时间片轮转法:图18 时间片轮转法先来先服务算法:图19 先来先服务算法五、用户使用说明这次的课程设计实验主要是模拟一个操作系统的各个功能算法,重点在于算法的描述,应用。当运行的时候会出现一个主界面,上面列出了该系统主要实现的功能,可以根据提示选择1.、进程调度2、贮存空间分配与回收3、模拟文件管理4、内存调度算法 5、银行家算法 6、 退出系统。选择完后就进入该模块,如果选择的是1即银行家算法,进去后界面也会有提示,1、新加作业,2,、为作业申请资源3、撤销作业4、查看资源情况、0退出系统,选择你想要操作的。会提示你相应的操作。如果选择的是2即模拟文件管理,进入后也有界面给予提示,但是这个模块有先后顺序,即应该先创建目录,之后在进行其他操作,我还加入了一个额外的功能,如果输入cd . 就会回到上一级目录里。如果选择的是3,即存储器管理,这个模块首先要在改程序在同一目录下建立一个空闲表,进入该模块后首先要输入改空闲表,例如,input.txt,如果该空闲表存在的话就会继续往下进行,根据提示做想要实现的操作。如果选择的是4,即进程调度,进入后可以选择P、优先数算法,R、时间片轮转法 F、先来先服务算法、E退出时间片轮转法的时间片由用户来定。这些模块中的退出都是退到主界面的,要想退出本系统,在主界面里有一个退出。六、总结与体会这次课程设计对我来说获益很大、体会很深,通过这次课程设计将所学的操作系统课程的知识用于实践,对所学的知识有了系统的了解、更深刻。在将各个模块连起来过正中首先要对各个模块都深入了解,不仅复习了所学的,以前不明白的现在明白了好多,而且对“操作系统”不再陌生,但是“操作系统“所要做的绝不是这么少的,所学的这些是远远不够的,希望还能有更深的了解。这次课程设计让我我熟练的练习了VC+6.0环境,更让那个我了解和运用 了linux操作系统,了解了OS内核结构,核心操作,以及最基本的OS管理。对以后学习有很大帮助。这次课程设计给我了很大的启示:无论学什么都要一步一个脚印,不能前面开始学很有劲头,后面就松懈了,要持之以恒。感谢老师耐心的教导,您认真的态度对我们很有帮助、很亲切,但对我来说是提升自身,我想我的IT之路还没走完,会有更深入的学习。再次感谢老师!参考文献1 李登实,徐宏云,计算机操作系统实验,北京,清华大学出版社,2000年9月。2汤小丹,梁红兵,计算机操作系统,西安,西安电子科技大学出版社,2007年5月。附录:程序清单源码附录:#include<stdio.h>#include<string.h>#include<iostream>using namespace std;#include<stdlib.h>#include<conio.h>#include<math.h>const int MAX_P=20;const int MAXA=10;const int MAXB=5;const int MAXC=7;typedef struct anode int a,b,c,/*三种资源总数*/remain_a,remain_b,remain_c/*三种资源剩余数*/; bank;typedef struct node1 char name20; int a,b,c,need_a,need_b,need_c; process;bank banker;process processesMAX_P;int quantity;/作业的数量 typedef struct bnode char name50; int type;/*0代表目录,1代表普通文件*/ struct bnode *next,/* 兄弟节点*/*sub,/*第一个子节点*/*father/*父节点*/; int size; /*文件的大小*/dirnode;dirnode *workdir;/当前工作目录 dirnode root;/根目录 char path100;/定义路径信息 const int MAXJOB = 100;/定义最大记录数typedef struct cnodeint start;int length;char tag20;job; job freesMAXJOB;/定义空闲区表 int free_quantity;job occupysMAXJOB;int occupy_quantity;typedef struct dnode char name10; int prio; int round; int cputime; int needtime; int count; char state; struct dnode *next;PCB;PCB *finish,*ready,*run,*r;int N;/银行家算法 /初始化函数void yinitial() int i; banker.a=MAXA; banker.b=MAXB; banker.c=MAXC; banker.remain_a=MAXA; banker.remain_b=MAXB; banker.remain_c=MAXC; for(i=0;i<MAX_P;i+) strcpy(processesi.name,""); processesi.a=0; processesi.b=0; processesi.c=0; processesi.need_a=0; processesi.need_b=0; processesi.need_c=0; /新加作业void add() char name20; int flag=0,t,need_a,need_b,need_c,i; cout<<endl; cout<<"新加作业" <<endl; cout<<"-"<<endl; cout<<"请输入新加作业名:" cin>>name; for(i=0;i<quantity;i+) if(!strcmp(processesi.name,name) flag=1;break; if(flag) cout<<"错误,作业以存在"<<endl; else cout<<"本作业所需A类资源:" cin>>need_a; cout<<"本作业所需B类资源:" cin>>need_b; cout<<"本作业所需C类资源:" ; cin>>need_c; t=1; if(need_a>banker.remain_a ) cout<<"错误,所需A类资源大于银行家所剩A类资源"<<endl; t=0; if(need_b>banker.remain_b ) cout<<"错误,所需B类资源大于银行家所剩B类资源"<<endl; t=0; if(need_c>banker.remain_c ) cout<<"错误,所需C类资源大于银行家所剩C类资源"<<endl; t=0; if(t) strcpy(processesquantity.name,name); processesquantity.need_a=need_a; processesquantity.need_b=need_b; processesquantity.need_c=need_c; quantity+; cout<<"新加作业成功"<<endl; else cout<<"新加作业失败"<<endl; /为作业申请资源void bid() char name20; int i,p,a,b,c,flag; cout<<endl<<"为作业申请资源"<<endl;/输出 cout<<"-" <<endl; cout<<"要申请资源作业名:" cin>>name;/输入 p=-1; for(i=0;i<quantity;i+) if(!strcmp(processesi.name,name) p=i;break; if(p!= -1) cout<<"该作业要申请A资源的数量:" cin>>a; cout<<"该作业要申请B资源的数量:" cin>>b; cout<<"该作业要申请C资源的数量:" cin>>c; flag=1; if(a>banker.remain_a)|(a>processesp.need_a-processesp.a) cout<<"错误,所申请A类资源大于银行家所剩A