电子科技大学---操作系统课程实验(二)
来源:互联网 发布:接单软件 编辑:程序博客网 时间:2024/06/07 01:57
前一篇文章贴出的是基本的实验思路以及要求,接下来我们用代码具体实现整个进程管理过程。由于本人比较喜欢用java开发,并且java写起来比c快多了,于是就写了一个java版的。思想都是一样的,语言不重要
系统目录:
整个系统主要是三个java代码文件:![这里写图片描述](http://img.blog.csdn.net/20170514183939198?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3ByaW5nY29kZXI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
代码分析
1.Main.java
public class Main { private static Scanner scanner =new Scanner(System.in); private static String command=null; public static void main(String args[]){ command=scanner.nextLine(); command=command.trim(); while(command!=""){ TestShell.exeCommand(command); command=scanner.nextLine(); command=command.trim(); } }}
主函数中没有什么,就是对控制面板输入的命令进行处理
2.PCB.java
PCB(process control block),进程控制块,是我们学习操作系统后遇到的第一个数据结构描述,它是对系统的进程进行管理的重要依据,和进程管理相关的操作无一不用到PCB中的内容。一般情况下,PCB中包含以下内容:
(1)进程标识符(内部,外部)
(2)处理机的信息(通用寄存器,指令计数器,PSW,用户的栈指针)。
(3)进程调度信息(进程状态,进程的优先级,进程调度所需的其它信息,事件)
(4)进程控制信息(程序的数据的地址,资源清单,进程同步和通信机制,链接指针)
由于这个试验中用不到这么多信息,所以我们的代码中也就没有写这么多。主要包括:进程名,进程ID,父进程,优先级,子进程等的一些简要信息
private int pid;//正在运行的process id private int prioirty; private String name; private String childName=null; private Map<String ,Integer> requestRes=new HashMap<>(); private int parentId; private int childId; private int state;
其中requestRes表示进程请求的资源,初始化的时候都是0,表示进程刚刚创建,还没有请求资源
此外我们在定义几个表示进程状态的常量:
public static final int STATE_RUNNING=0; public static final int STATE_BLOCKED=1; public static final int STATE_READY=2; public static final int STATE_DESTORYED=3;
3.Log.java
由于需要输出一些文字,包括一些必要的进程信息,还有命令处理的出错信息,其实就是嫌弃System.out.println(“”)太长了,这里我们写一个工具类,便于开发
public class Log { public static void e(String info){ System.out.println(info); } public static void e(String tag,String info){ System.out.println(tag+":"+info); }}
4.TestShell.java
接下来就是最重要的TestShell.java 了。在这个类中,我们首先将得到的命令进行解析,在解析的时候要注意一下几点:
(1)命令的单词之间只能有一个空格,并且只能是空格
(2)命令解析到具体的命令的时候需要对命令的长度进行判断,如果命令的参数个数不符合要求,则给出合理的提示,包括命令的使用方法
(3)其次在进行参数的正确性判断,对不符合规定的参数进行提示,并给出正确参数的提示,便于用户改正错误
(4)用户的第一条命令只能是init,用于创建系统的init进程(为什么这么干,额实验老师就是这么要求的)
接下来就是具体的命令的解析以及执行了
首先先定义两个队列,存放就绪进程跟阻塞进程:
private static List<PCB> ready=new ArrayList<>(); private static List<PCB> blocked=new ArrayList<>();
其次是定义一个系统资源队列,这里文档中要求的资源 以及个数如下:
R1—1个
R2—2个
R3—3个
R4—4个
private static Map<String ,Integer> avaliableRes=new HashMap<>();
在init命令执行的时候进行系统资源的初始化,也可以将此代码写在静态代码块中
// 初始化资源 avaliableRes.put("R1",1); avaliableRes.put("R2",2); avaliableRes.put("R3",3); avaliableRes.put("R4",4);
同时创建一个init进程,他的优先级是0,为系统级进程,同时由于还没有子进程,所以我们将他的子进程id设置成-1
整个代码如下:
/** * init 进程启动 */ public static void init(){ PCB initPrecess=new PCB(0,-1,"init",0); initPrecess.setChildId(-1); //ready.add(initPrecess); // 初始化资源 avaliableRes.put("R1",1); avaliableRes.put("R2",2); avaliableRes.put("R3",3); avaliableRes.put("R4",4); //从ready中拿到一个进程开始执行,也就是init进程 currentProcess=initPrecess; }
创建新进程:
首先创建一个新的进程,他的父进程就是当前正在运行的进程,我们从当前进程中得到他的父进程的信息,同时改写当前进程的childId,将他设置成当前进程的id。同时将这个新建的进程放在就绪队列中准备被调度
/** * 创建新进程,并将父进程与子进程联系起来, * 创建后进入就绪队列,不进行调度 * @param parentId * @param name * @param priority */ public static void createNewTread(int parentId,String name,int priority){ pid++; PCB pcb=new PCB(pid,parentId,name,priority); pcb.setChildId(-1); currentProcess.setChildId(pid); currentProcess.setChildName(name ); ready.add(pcb); }
进程的阻塞:
进程在请求资源的时候如果系统剩余的资源不够,那么进程将进行阻塞,这个时候如果进程已经得到了一部分 资源,那么这部分资源他将不会释放,也就是带着资源进行阻塞。一个正在运行中的进程阻塞的时候,系统除了将他调入阻塞队列中,还会从就绪队列中调出一个优先权最高的进程执行,如果优先级都是一样的,那么调度最先进入队列的那个进程:
/** * 正在运行的进程请求分配资源 * @return true:成功 false 资源不够失败 */ public static boolean allocateRes(String name,int num){ int availNum=avaliableRes.get(name)-num; Map curPossMap=currentProcess.getRequestRes(); if (availNum<0){ return false; } int possNum= (int) curPossMap.get(name); curPossMap.put(name,num+possNum); avaliableRes.put(name, availNum); return true; }
如果没有成功,则从ready队列中调用一个就绪进程
if(!success){ System.out.println("no enough res"); System.out.println("current process --name :"+currentProcess.getName()+" blocked"); blockCurrentProcess(); getProcessFromReady(3); }
时间片的切换:
当一个进程的时间片用完的时候需要切换时间片,这个时候需要将当前的进程调入就绪队列中,然后在从就绪队列中调出一个优先级最高的进程执行
/** * 切换进程 */ private static void timeOut(){ //不释放资源 getProcessFromReady(2); }
进程的结束:
当进程被结束或者是正常的结束的时候,首先会释放自己已有的资源,同时如果这个进程是正在运行的进程,系统还会从就绪 队列中调一个进程执行,同时进程的结束是一个递归的过程,被结束的进程还会结束他的子进程。当有进程被结束就可能有资源被释放出来,所以在此同时,我们还需要对资源进行回收,回收的资源如果阻塞队列中有进程,那么就需要判断资源能否满足进程的需求,如果能满足则需要将资源分配给进程。同时将进程调度到就绪队列中,在从就绪队列中调出应该得到时间片的那个进程。所以这是一个复杂的工作
public static boolean destoryThread(String name){ PCB delProcess=null; boolean find=false; /** * 删除ready中的 */ for (Iterator<PCB> it = ready.iterator(); it.hasNext();) { PCB value = it.next(); if (value.getName().equals(name)) { delProcess=value; find=true; it.remove(); continue; } } /** * 删除blocked中的 */ if (!find){ for (Iterator<PCB> it = blocked.iterator(); it.hasNext();) { PCB value = it.next(); if (value.getName().equals(name)) { delProcess=value; find=true; it.remove(); continue; } } } /** * 删除正在运行中的 */ if(currentProcess.getName().equals(name)){ delProcess=currentProcess; find=true; } if(!find){ return false; } /** * 释放资源 */ if(delProcess!=null){ Map resMap =delProcess.getRequestRes(); releaseProceeRes(resMap); changeBlockState(); //如果删除的是当前正在运行的进程 if(delProcess.getPid()==currentProcess.getPid()){ currentProcess.setState(PCB.STATE_DESTORYED); } } if(delProcess.getChildId()>0){ destoryThread(delProcess.getChildName()); } return true ; }
进程的调出:
那么这里就有一个很严肃的问题了,那就是如何从就绪队列中调出该得到时间片的进程了。这里分成三类,一个是直接从就绪队列中调出一个应该执行的进程接下来执行,这种情况为阻塞发生的时候,已经进程被结束的时候。还有一种是需要将当前正在运行的进程放入就绪队列在进行调出的。这里我们用数字2,3,4分开这三种情况
2—timeout 的时候调用,一定从ready中取一个进程,再将当前进程调入就绪队列
3—当前进程被阻塞的时候一定从ready中取一个,当前进程进入阻塞队列
4—当前进程被结束的时候,一定从ready中取出一个进程
* 从一个队列中得到process分配cpu执行 * @param :1 readyList 2:blockedList * @return 1 优先ready队列 */ private static void getProcessFromReady(int i ){ if(ready.size()==0){ Log.e("first","return"); return ; } //寻找ready中优先级最高的进程 PCB cProcess=null; int maxProirity=-1; for (Iterator<PCB> it = ready.iterator(); it.hasNext();) { PCB value = it.next(); if(value.getPrioirty()>maxProirity){ cProcess=value; maxProirity=value.getPrioirty(); } } switch (i){ //timeout 的时候调用,一定从ready中取一个进程 case 2: if(cProcess!=null){ if(cProcess.getPrioirty()<currentProcess.getPrioirty()){ return; } ready.add(currentProcess); currentProcess=cProcess; ready.remove(cProcess); return; } break; //当前进程被阻塞的时候一定从ready中取一个 case 3: blocked.add(currentProcess); currentProcess=cProcess; ready.remove(cProcess); break; //当前进程被结束的时候 case 4: currentProcess=cProcess; ready.remove(cProcess); break; } }
当资源被释放的时候我们又需要对阻塞队列中的进程进行调度了:
1.释放当前进程的资源:
/** * * @param name 资源名 * @param num 数目 * @return 是否成功释放 */ public static boolean relCurProRes(String name,int num){ Map curResMap=currentProcess.getRequestRes(); int n = (int) curResMap.get(name); if(num>n){ System.out.println("res release too much for possess"); return false; } avaliableRes.put(name,avaliableRes.get(name)+num); curResMap.put(name,n-num); return true; }
2.对阻塞队列中的进程进行调度
/** * 当一个进程被结束掉之后,释放资源,对释放后的资源进行判断, * 如果该资源能够让阻塞队列中的process 激活则激活并进入ready队列 */ public static boolean changeBlockState(){ for(int i =0;i<blocked.size();i++){ PCB p=blocked.get(i); //如果系统剩余资源够用,则为阻塞队列的process分配资源,并将改process 移到ready中 if((avaliableRes.get("R1")>=p.getRequestRes().get("R1"))&& (avaliableRes.get("R2")>=p.getRequestRes().get("R2"))&& (avaliableRes.get("R3")>=p.getRequestRes().get("R3"))&& (avaliableRes.get("R4")>=p.getRequestRes().get("R4")) ){ ready.add(p); blocked.remove(p); } } return true; }
其实很容易看出来这个函数里面写错了,少了减少剩余系统资源的部分,由于老师给的例子不涉的特殊性,本人暂时没时间改了,就暂时不弄了,管他的,先交报告,错误的地方请读者自行改正。
在此整个进程调度的算法就基本完成,同时还有一些命令的解析函数没有贴上来,感觉太多了。需要整个项目的可以自行下载:
URL=http://download.csdn.net/detail/springcoder/9842209
注意:这里 在队列中删除item的时候用了迭代器,读者可以试试不用迭代器,这样的话会报错。主要原因是因为list没有加锁的原因,大家也可以试试对list进行加锁访问
转载请注明地址:http://blog.csdn.net/springcoder/article/details/72049041
- 电子科技大学---操作系统课程实验(二)
- 电子科技大学---操作系统课程实验(一)
- 桂林电子科技大学操作系统课程设计(二)
- 操作系统课程实验报告(三)
- 操作系统课程实验报告(四)
- 桂林电子科技大学操作系统课程设计(一)
- 数据结构课程上机实验题(二)
- FZU操作系统课程实验 实验一
- 电子科技大学-编译原理实验
- 华师 操作系统实验 实验二
- 操作系统实验二实验报告
- 操作系统实验二
- MIT操作系统课程CS6.828实验(2) —— 实验工具指导
- 软件工程课程实验报告:实验二
- Oracle之课程实验二(数据字典)
- 操作系统实验二 作业调度
- 操作系统实验二 进程管理
- 操作系统实验二之管道通信实验
- 前端书写规范建议
- 运算
- 学习【OpenCV入门教程之六】 创建Trackbar & 图像对比度、亮度值调整
- java字符串
- python基础(set)补充
- 电子科技大学---操作系统课程实验(二)
- 树莓派3B设置静态IP连接无线WIFI
- 各种前端问题汇总,持续更新中.........
- python基础set
- 二分查找及其变形整理
- vue2.0双向绑定不起效果
- 如何从商品详情页面下载源图片
- C. Naming Company 贪心
- 调试 Dockerfile