基于Java的模拟操作系统设计 源码
# 模拟操作系统## 需求分析明确陈述说明程序设计的任务,强调的是程序要做什么,主要包括:任务要求:模拟一个采用多道程序设计方法的单用户操作系统,该操作系统包括进程管理、存储管理、设备管理、文件管理和用户接口四部分。输入的形式和输入值的范围;① 从用户界面输入字符串形式的 8 个命令,如下:创建文件: create删除文件: delete显示文件: type拷贝文件: copy建立目录: mkdir删除空目录: rmdir进入退出某个目录::cd新建可执行文件:newexecreate 新建文件时,type 打开文件,从用户界面输入文本内容,并点击保存。目前仅支持第一次保存,暂不支持修改。输出的形式;① 进程管理部分系统时间,相对时钟(时间片)、正运行进程 ID、正在执行指令、进程中间执行结果、进程最终结果以及就绪队列、阻塞队列(均以字符串形式输出并显示于用户界面)② 存储管理部分内存分区情况(列表形式输出显示)③ 设备管理部分种设备的使用情况和相应等待使用的进程 ID(列表形式输出显示)④ 文件管理部分文件树状目录、文本文件的内容和磁盘使用情况(文件内容字符串形式输出显示,单个磁盘用红蓝小方块表示)⑤ 用户接口部分显示软件系统的界面程序所能达到的功能;总体功能:实现一个采用多道程序设计方法的单用户操作系统,包括进程管理、存储管理、设备管理、文件管理和用户接口四部分。① 进程管理部分功能实现简单的 CPU,包括指令的读取、解析、执行等实现系统时钟,控制 CPU 和系统的节拍实现主要的寄存器进程管理主要包括进程调度、进程的创建和撤销、进程的阻塞和唤醒, 中断作用的实现② 存储管理部分功能划分系统区和用户区实现内存空间的分配和回收、存储保护(采用动态分区存储管理和首次适配)③ 设备管理部分功能实现设备的分配和回收,可实现进程的阻塞和唤醒,并管理等待设备的进程设备使用倒计时来表示占用某个设备④ 文件管理部分功能实现了进入退出目录、新建文件、删除文件、复制文件、删除空目录、新建 exe 文件、读取文件。显示文件目录树显示磁盘使用情况,红色表示未被占用,蓝色表示已经被占用。⑤ 用户接口部分将进程执行中的各种状态、数据以及内存、磁盘使用情况显示出来可输入各种文件命令,响应并显示各种文件命令操作测试数据:包括正确的输入及其输出结果和含有错误的输入及其输出结果。① 若可执行文件是:```c++X=12X++!A7X--!B5end```模拟 CPU 在执行时,应能显示每一条指令、执行中间结果、最终结果以及对应进程 ID;内存、进程队列、设备以及磁盘方面均应有相应的实时显示创建文件正确输入 create gyk.txt,正确输出 目录树更新,在该路径下生成 gyk.txt。错误输入 create gykk.txt错误输出 文本域提示文件命名不正确删除文件正确输入 delete gyk.txt正确输出 目录树更新,该路径下的 gyk.txt 消失,对应磁盘块变为红色错误输入 delete gykk.txt错误输出 文本域提示文件名不正确错误输入 delete g.txt错误输出 文本域提示文件不存在显示文件:正确输入 type gyk.txt正确输出 文本域显示文件内容,如果是第一次打开,输入内容后点击保存即可保存。磁盘块更新。错误输入 type gykk.txt错误输出 文本域提示文件名不正确拷贝文件:正确输入 copy gyk.txt aaa/bbb正确输出 目录树更新,磁盘块更新,aaa/bbb 下出现 gyk.txt错误输入 copy gyk.txt aaa/ccc错误输出 文本域提示路径不存在建立目录:正确输入 mkdir aaa正确输出 目录树更新错误输入 makdir aaaa错误输出 文本域提示目录名错误删除空目录:正确输入 rmdir aaa输入 如果该目录下没有文件,则可以删除,更新目录树,更新磁盘块;如果该目录下有文件或者目录,则提示该目录不为空。进入退出某个目录:正确输入 cd aaa/cd ..输入 命令行更新 root>aaa:,root:,如果在 root:情况下输入 cd .. 则会提示错误新建可执行文件:正确输入 newexe eee.exe ,在文本框中写入指令,并点击保存正确输出 目录树更新,磁盘块更新。## 概要设计说明本程序中用到的所有抽象数据类型的定义、主程序的流程以及各程序模块之间的层次 (调用)关系。## 详细设计实现概要设计中定义的所有数据类型,对每个操作只需要写出伪码算法;对主程序和其他模 块也都需要写出伪码算法(伪码算法达到的详细程度应能够按照伪码算法在计算机键盘上直接输 入高级程序设计语言程序);画出函数的调用关系图。存储管理主程序伪代码:````c++public class MemoryManage {//内存分区表//申请pcb总数count//pcb表//进程表private static total_Size total = new total_Size();private static int pcbCount = 10;private static Listpcbs = new ArrayList();private static Listjobs = new ArrayList();}public static boolean 申请空白 PCB(PCBManager pcb){if(申请count>10) {申请失败;}else {申请成功;}}public static int 请求分配内存(int 进程标识符,int 大小,String 文件路径) throws IOException{//创建进程对象//获取内存分区表//按内存地址排序for(< 内存分区表总长度){if(未分配){if(分区大小>进程所需内存大小) {//内存申请成功total.alloc(i, job);//调用分配算法分配内存}}}if(>分区表总长度) {//内存申请失败}//返回内存起始地址 }public static void 释放内存(int 起始地址){//获取分区表Listlsize = total.getList();int i ;int index = -1;//标记符for(i< 内存分区表总长度){if(找到匹配的内存的起始地址){for(int j=0; j<进程表长度; j++) {if(找到匹配的进程标识符){```c++//回收分区total.search(jobs.get(j));jobs.remove(j);//释放内存Return;}}}}//否则释放内存失败}public static boolean 释放 pcb(int index){int j;for(jif(找到匹配的进程标识符){//删除pcbpcbs.remove(j);System.out.println("进程控制块为"+j+"已删除");break;}}if(j>pcb总数量) {System.out.println("没有该进程控制块");return false;}elsereturn true;}public static void sort(Listlsize) {//按内存地址排序算法}public static void memoryList() {//打印分区信息}```//回收分区total.search(jobs.get(j));jobs.remove(j);//释放内存Return;}}}}//否则释放内存失败}public static boolean 释放 pcb(int index){int j;for(jif(找到匹配的进程标识符){//删除pcbpcbs.remove(j);System.out.println("进程控制块为"+j+"已删除");break;}}if(j>pcb总数量) {System.out.println("没有该进程控制块");return false;}elsereturn true;}public static void sort(Listlsize) {//按内存地址排序算法}public static void memoryList() {//打印分区信息}````其他模块伪代码:单独分区模块伪代码:```c++public class Size {//start addressprivate int start;//起始地址private int space;//空间大小private int states = -1;//分配状态private ArrayListins = new ArrayList();public Size(int start,int space )}public Size(int start, int space, int states) {}public int getStart() {}public void setStart(int start) {}public int getSpace() {}public void setSpace{}public int getState() {}Public void setState() {}public void setIns(String filename) throws IOException{}public String getIns(int i) {}```分区表代码```c++public class total_Size {//分区表private Listblock_list = new LinkedList();//min blockprivate int minSize = 0;public total_Size() {Size size = new Size(0,512); // 分配内存block_list.add(size);//add}public ListgetList() {}public void setList(Listblock_list) {}public boolean JudgeSzie(int i {}public void alloc (int index, process job) throws IOException {//分配算法 首次适配Size size = block_list.get(index);if(size.getSpace() - job.getSize() <= this.minSize) {size.setState(job.getIndex());}if(size.getSpace()-job.getSize()>this.minSize) {int newStart = size.getStart()+ job.getSize();int newSpace = size.getSpace() - job.getSize();Size newSize = new Size(newStart,newSpace);block_list.add(newSize);size.setSpace(job.getSize());size.setState(job.getIndex());size.setIns(job.getFilename());}//return hole.getStartAddress();}//进程结束,回收分区public void search(process job) {Size size =null;int flag = -1 ;//记录当前位置for(int i=0; i//找到被回收的分区if(block_list.get(i).getState() ==job.getIndex()) {// 设置自己为空闲}}if(flag == -1) {return;}//当前分区的后面的分区地址 当前adrs+spaceint nextAdrs = size.getStart() + size.getSpace();//合并空闲分区for(int i=0; iif(JudgeSzie(i)) {Size nowSize = block_list.get(i);if(nowSize.getStart()+nowSize.getSpace() == size.getStart()) {merge(i,flag);}}}}public void merge(int i, int j) {//合并分区算法i_size.setSpace(i_size.getSpace() + j_siz.getSpace());block_list.remove(j);}```进程模块伪代码```c++public class process {private int size;private int index;private String filename;public process (int index,int size, String filename) { //初始化 }public int getIndex() {}public void setIndex(int index) {}public int getSize() {}public void setSize(int size) {}public String getFilename() {}public void setFilename(String filename) {}```设备```c++package com.os;import java.util.LinkedList;// 设备管理类public class DeviceManagement {// 单例private static DeviceManagement instance;// 设备的数量private static final int TOTAL_A = 2;private static final int TOTAL_B = 3;private static final int TOTAL_C = 3;private LinkedListusingList=new LinkedList();private LinkedListwaitingList=new LinkedList();private DeviceManagement () {}// 获取类的实例public static synchronized DeviceManagement getInstance() {if (instance == null) {instance = new DeviceManagement();}return instance;}// 一个进程运行的时候public void OnProcessRun( Process pro, Device dev){int devCount = 0;DeviceStatus s = new DeviceStatus();pro = pro;dev = dev;// 遍历使用队列,如果有可用的设备,则将信息加入到usingQueue中,如果没有可用的设备,则把信息添加到waitingQueue中for (DeviceStatus x : usingList) {if( x.dev.getName().compareTo(dev.getName())==0 ){devCount++;if( dev.getName().compareTo("A")==0 ) {// 如果大于了最大设备个数,则加入到等待队列if( devCount>=TOTAL_A ) {waitingList.offer(s);return;}}else {if( devCount>=TOTAL_B || devCount>=TOTAL_C ) {waitingList.offer(s);return;}}}}// 如果没有超出最大数量,那么则使用此设备usingList.offer(s);}// 一个进程结束的时候public void OnProcessStop( Process pro ){Device reDevice = new Device();// 设备使用完毕,清除相关条目信息,然后把等待队列中的进程加入到列表中for (DeviceStatus x : usingList) {if( x.pro.getName().compareTo(pro.getName())==0 ) {reDevice = x.dev;usingList.remove(x);break;}}// 从等待队列中把使用此设备的进程取出for (DeviceStatus x : waitingList) {if( x.dev.getName().compareTo(reDevice.getName())==0 ) {usingList.offer(x);waitingList.remove(x);break;}}}// 显示目前设备的占用情况public void ShowStatus() {System.out.println("【设备使用情况】");for (DeviceStatus x : usingList) {System.out.println("进程:" + x.pro.getName() + " - 设备:" + x.dev.getName());}System.out.println("【等待队列】");for (DeviceStatus x : waitingList) {System.out.println("进程:" + x.pro.getName() + " - 设备:" + x.dev.getName());}}}```文件模块- 调试分析- 内容包括:- 调试过程中遇到的问题是如何解决的以及对设计与实现的讨论和分析;- 算法的时间复杂性(包括基本操作和其他算法的时间复杂性的分析)和改进设想;- 设计过程的经验和体会;设备:通过对这次操作系统课程设计的亲自参与和操作,使我深刻体会到了:只要你想做只要你想学没有弄不懂得事情,工程里面也不能不在乎细节,等等。感觉很受益匪浅。懂得了操作系统包括的四部分内容:文件管理和用户接口、存储管理、设备管理、进程管理之间的内在联系。加深了我对这门课程的理解。锻炼了自己在考虑全局也不是细节的能力。文件:文件个人觉得是整个系统中最为复杂的部分,从看懂文档到慢慢了解,思考构造,花了很长的时间。考虑到对 Java 界面不够熟悉,所以采用了用命令行来执行操作的方法。存储文件后要改变原目录中的起始盘块和文件分配表是比较难实现的步骤。内存:本次的课程设计我负责的是存储管理部分,说实话,这其实对我来说算是比较大难度的课程设计,主要是因为本身的 Java 程序设计并没有学的很扎实,其次对操作系统的许多课程知识也开始遗忘,一开始的确是无从下手,后来,通过询问班级里 Java 程序设计厉害的同学,才开始有了思路。通过学习的知识,我知道要开始一个进程要先向内存申请分配内存空间,而进程结束后,要释放已分配的内存空间,而如何分配内存空间给所需要的进程又是依靠动态分区存储管理方式,采用首次适配、下次适配或者最佳适配算法来动态管理存储方式,而每个内存分区表都是由一个一个的分区组成,所以我就是沿着这个思路,由小及大开始解决问题。先从每个分区起手,定义一个分区的类(Size.class),类中包含每个分区起始地址、分区大小、分配状态的 get/set 方法,然后用链表结构 List构成分区表,采用首次适配的分配方式来构造内存分配方法,并构造内存回收释放方法,接下是进程类(Process.class),该类包含进程控制块标识符、大小、文件所在路径的 get/set 方法,最后是主类实现从申请空白 PCB 块,请求分配内存,回收释放的全过程。通过这次的课程设计,学会了更清晰、由小及大的思考方式,学会将大的问题逐步细分,分解成小的问题来思考,然后再从小的问题一步一步解决,最终解决大的问题,其次同学们也帮助了很多,给了我许多提醒和值得参考的方法,这次的课程设计实验收货的确不少,在巩固了所学的知识的同时,也学会了更进一步的实践,提高了实践能力,也能更深一层的了解操作系统的操作原理。界面: 这次操作系统课程设计让我深刻体会到了 UI 设计的双面性.刚开始团队要求的 Java 编写(我对 Java 几乎了解甚少),后来通过百度查询运用了 windowBuilder 插件进行拖拉操作,后期修改部分代码完成了系统的界面操作。实现过程中出现的主要问题及解决方法。设备:在模拟设备管理的功能的过程中,很多次不可避免的碰到了死锁的问题,遇到过很多难题,经历过难题得不到解决的过程,但是通过查阅资料,收获不菲,很好地理解了银行家算法,达到了课程设计的目的,增强了动手能力。文件:问题集中于如何模拟磁盘、如何存入文件,如何修改文件分配表,如何记录目录项,如何显示目录等等。模拟磁盘利用了 byte 数组,保存到 disk 文件中,方便下次读取。目录的显示用了 swing 的 jtree,通过遍历磁盘中的目录项添加到节点中,形成树。用 byte 数组模拟磁盘。再界面上输入内容后,提取内容转化为字节保存到 byte 数组中,解决了文件存储问题。界面:JLabel 无法显示背景颜色,后来用了 Panel 来代替使用.## 用户使用说明打开系统后,文件操作模块支持以下指令,用户可在 root:后输入指令,每一步的操作仅限于当前目录下的内容。cd,cd xxx 进入某个目录,如果有错误,会在下面的灰色文本域内显示;cd .. 是返回上一层。makdir,makdir xxx 新建目录,仅支持最多 3 个字符,根目录只支持 8 个目录。如果有错误,会在下面灰色文本域内显示。create,create xxx.txt 建立文本文件,仅支持最多 3 个字符,根目录不能建立文件,如果有错误,会在下面灰色文本域内显示。type,type xxx.txt 打开文本文件,如果有错误,会在下面灰色文本域内显示。如果第一次打开文件,文件内没有内容可添加,并按保存按钮保存内容。暂不支持修改内容。delete,delete xxx.txt 删除文件,如果有错误,会在下面灰色文本域内显示。rmdir,rmdir xxx 删除空目录,如果有错误,会在下面灰色文本域内显示。暂不支持删除非空目录。copy,copy xxx.txt xxx/xxx 复制文件到某个目录(绝对路径),如果有错误,会在下面灰色文本域内显示。Newexe,newexe xxx.exe 新建可执行文件,仅支持最多 3 个字符,根目录不能建立文件,如果有错误,会在下面灰色文本域内显示。新建后下面灰色文本域会变为白色,可在里面输入指令,每次输入一条指令敲击一次回车。例如(x=1 回车 x=2 回车 end)。每次执行操作后,可以看到下方磁盘块发生变化,蓝色代表被占用,右侧是目录树可以查看当前目录状况。## 测试与运行结果列出你的测试结果和运行情况(即运行时的关键画面),包括输入和输出。这里的测试数 据应该完整和严格,最好多于需求分析中所列。值得注意的是,报告的各种文档资料,要在程序开发的过程中逐渐充实形成,而不是最后补 写。必要时可在报告中附部分关键源代码,但不需要附全部源代码。cd aaa 进入 aaa 目录cd .. 退回上级目录makdir b 在 aaa 目录下建立 b 目录create gyk.txt 在 aaa 目录下建立 gyk.txt 文件type gyk.txt 打开 gyk.txt 文件当前文件内容为空,所以文本域内是空白的,输入文字,点击保存,并再次打开,文字被保存delete gyk.txt 删除 gyk.txt 文件```c++Delete bbb.txt```rmdir b 删除 b 目录newexe ggg.exe 新建 exe 文件