最近在学操作系统,老师的第一个实验要求——实现动态优先级进程调度算法。在度娘上也搜到了些,借鉴了一位大佬的设计思想,用java实现了简单的一个进程调度算法。
1. 采用最高优先数的调度算法(即把处理机分配给优先数最高的进程)。 注:数字越小,优先级越高,当然我偷懒都设为正整数,你好我好大家好!
2. 每个进程有一个进程控制块(PCB)表示。进程控制块可以包含如下信息:进程名、优先数、到达时间、需要运行时间、已用CPU时间、进程状态等等。
3. 进程信息可以手动输入也可以用随机数产生。
4. 每个进程的状态可以是就绪W(Wait)、运行R(Run)、或完成F(Finish)三种状态之一。
5. 就绪进程获得CPU后都只能运行一个时间片。用已占用CPU时间加1表示。
对于这个模拟动态优先级的算法来说,可以用不同的语言来实现,比如C/C++,而网上用前面算法来执行的也占多数,但因为在学java,算了,就用java写这个算法吧,类的设计思想借鉴了一位大佬的算法,以前确实没写过,在此感谢,但是我忘了他的博客,下次找到了告诉你们(hhh)。
1. 根据实验要求2,因为要存储进程的相关信息,那么首先应该做的就是设计一个Pcb类,不然到时候连进程的信息都无法获取,那就凉了。(知道你们喜欢代码,诺,直接上了)。哦对了,设计相关属性的时候,不要忘了get()和set()方法,要对值进行访问,这是必不可少的,虽然开发环境会自动产生属性的对应get方法和set方法,但是养成好习惯不好吗?
Pcb.java
/** * @author GoldenRetriever */ public class Pcb { /** * 进程名 */ private String pcbName; /** * 进程优先级 */ private int priority; /** * 进程到达时间 */ private int pcbArrivalTime; /** * 进程需要运行时间 */ private int pcbNeedRunningTime; /** * 进程已用CPU时间 */ private int pcbHasUsedTime = 0 ; /** * 进程状态 W(wait等待),R(run运行),F(finish完成) */ private String pcbState = "Wait"; /** * get and set */ public String getPcbName() { return pcbName; } public void setPcbName(String pcbName) { this.pcbName = pcbName; } public int getPriority(){ return priority; } public void setPriority(int priority) { this.priority = priority; } public int getPcbArrivalTime() { return pcbArrivalTime; } public void setPcbArrivalTime(int pcbArrivalTime) { this.pcbArrivalTime = pcbArrivalTime; } public int getPcbNeedRunningTime() { return pcbNeedRunningTime; } public void setPcbNeedRunningTime(int needRunningTime) { this.pcbNeedRunningTime = needRunningTime; } public int getPcbHasUsedTime() { return pcbHasUsedTime; } public void setPcbHasUsedTime(int time) { this.pcbHasUsedTime = time; } public String getPcbState() { return pcbState; } public void setPcbState(String w) { this.pcbState = w; } @Override public String toString(){ return "Pcb{ " + "pcbName =" + pcbName + " " + ", priority =" + priority + ", pcbArrivalTime =" + pcbArrivalTime + ", pcnNeedRunningTime =" + pcbNeedRunningTime + ", pcbHasUsedTime =" + pcbHasUsedTime + ", pcbState =" + pcbState + "}"; } }这里重写了toString()方法,当然是为了更好的输出了!(关于重写与重载的区别,忘了的朋友可以去下面看看) 重载与重写的区别 github
2. 管理进程信息的类写完了,那么接下来干嘛呢?毫无疑问,你需要的是进程执行过程中调用的方法,比如初始化进程啊,排序啊,判断进程是否结束啊等等。有人或许会问,为什么不在Pcb类中写,这个嘛,你不觉得写在一起好挤吗? 那个,需要些什么方法呢?分析分析。。。
初始化进程的方法 这个总要吧,你不能只有一个Pcb类,却不给人家赋值发挥作用吧,那不是占着那啥不那啥嘛。当然你要实在不想动手,那就写个方法给人家自动赋值呗,这多爽,一身轻松!
排序方法 这个也要吧。进程都来了,然后发现不知道谁是老大,谁先执行,那岂不是很尴尬。不行不行,这个得加上。那怎么排呢?别忘了我们实验的流程,每次都执行最高优先级的进程。那要是优先级都相同,怎么办捏?那就按到达时间先后来排嘛,那要是到达时间也相同呢?哪有那么多要是,听我的,我说没有就是没有(小声bb,都一样,亲兄弟还明算账啊,随便啦! )
判断进程结束方法 这个当然也要,不然怎么结束。不要真不行
调度算法 这个给个面子,加上。main()方法里肯定要调用它的,不然前面设计那么多方法干啥。有人可能会说,直接一个一个调用不就行了吗,搞那么多幺儿子(其实我是吃了没事干hhh)
还有吗? 其实还真有,但那是小事,都是小事了,就没有必要明面上说了。
说了这么多,大佬估计一下就懂了,直接下一篇博客,搞不好嘴里还骂骂咧咧地说道:“这肯定是个sb,写的啥玩意啊。”没事,咱不生气,肯定还有好学者,目不转睛的盯着屏幕,仔细研究,“md,代码在哪呢?” 这么多方法,再搞个类封装一下吧,我就叫它DynamicPriority.java好了。
DynamicPriority.java
import java.util.*; import java.util.Random; /** * @author GoldenRetriever */ public class DynamicPriority { /** * 进程初始化信息(小蜜蜂输入法) * @param pcb 进程 * @return 返回一个初始化好了的pcb进程 */ public static Pcb initByInput(Pcb pcb) { Scanner scanner = new Scanner(System.in); System.out.println("请输入进程名称:如(进程1)"); pcb.setPcbName(scanner.nextLine()); System.out.println("请输入进程优先数:如(5)"); pcb.setPriority(scanner.nextInt()); System.out.println("请输入进程到达时间:如(1)"); pcb.setPcbArrivalTime(scanner.nextInt()); System.out.println("请输入进程需要运行时间:如(3)"); pcb.setPcbNeedRunningTime(scanner.nextInt()); return pcb; } /** * 进程初始化信息(懒者必备,没错就是我) * @param pcb 进程 * @return 返回一个初始化好了的pcb进程 */ public static Pcb initByRandom(Pcb pcb) { Scanner scanner = new Scanner(System.in); Random random = new Random(); String s = getRandomString(4); pcb.setPcbName(s); //生成的随机数字在[1,7)之间 int priorityValue = random.nextInt(6)+1; pcb.setPriority(priorityValue); int arrivalTimeValue = random.nextInt(6)+1 ; pcb.setPcbArrivalTime(arrivalTimeValue); int needRunningTimeValue = random.nextInt(6) +1; pcb.setPcbNeedRunningTime(needRunningTimeValue); return pcb; } /** * 获取随机的字符串方法 * @param length 字符串长度 * @return 返回一个字符串 */ public static String getRandomString(int length){ String str="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; Random random=new Random(); StringBuffer sb =new StringBuffer(); for(int i=0;i<length;i++){ int number=random.nextInt(62); sb.append(str.charAt(number)); } return sb.toString(); } /** * 先按照优先度排序,优先度相同的按照到达时间去排序 * @param pcb 进程列表 */ public static void sortByPriorityAndArrivalTime(List<Pcb> pcb){ //使用list中的自定义条件排序方法 pcb.sort((pcb1, pcb2) -> { int cr = 0; //先按优先级排升序,数字越小,优先级越高。 int a = pcb1.getPriority() - pcb2.getPriority(); if (a != 0) { cr = (a < 0) ? -1 : 3; } else { //再按到达时间排升序 a = pcb1.getPcbArrivalTime() - pcb2.getPcbArrivalTime(); if (a != 0) { cr = (a > 0) ? 2 : -2; } } return cr; }); for(Pcb afterPcb: pcb){ System.out.println("afterSort: "+ afterPcb); } } /** * 进程开始运行方法 * @param pcb 进程 * @returnp pcb */ public static Pcb hasUsedTimeAdd1(Pcb pcb){ int time = pcb.getPcbHasUsedTime(); time++; pcb.setPcbHasUsedTime(time); System.out.println("进程" + pcb.getPcbName() + "运行一个时间片"); pcb.setPcbState("Run"); return pcb; } /** * 判断进程是否完成方法 * @param pcb 优先级最高的进程 * @param pcbs 就绪队列中的进程列表 * @param execpcbs 执行队列中的进程列表 */ public static void isTimeToRunningTime(Pcb pcb, List<Pcb> pcbs, List<Pcb> execpcbs){ //临时队列,将完成了的进程加入到temp中 List<Pcb> temp = new ArrayList<>(); //进程的已用CPU时间等于需要运行时间 if(pcb.getPcbHasUsedTime() == pcb.getPcbNeedRunningTime()){ //进程完成,设置进程状态为Finish pcb.setPcbState("Finish"); System.out.println("进程" + pcb.getPcbName() + "已完成"); //就绪队列删除完成进程,执行队列删除已完成队列 System.out.println("FinishedPcbInfo:"+pcb.toString()); System.out.println("***********"); pcbs.remove(pcb); execpcbs.remove(pcb); }else{ //进程优先数加1。 int n = pcb.getPriority(); n++; pcb.setPriority(n); System.out.println("进程"+ pcb.getPcbName() + "" + "优先数+1"); } } /** * 调度算法函数,最终将需要按顺序执行的进程放入execpcbs中 * @param pcbs 输入队列 * @param execpcbs 执行队列 */ public static void dispatchpcb(List<Pcb> pcbs, List<Pcb> execpcbs){ //中间队列,暂存从输入队列中挑选出的进程 List<Pcb> tempPcb = new ArrayList<>(); while (!pcbs.isEmpty()){ //排序 DynamicPriority.sortByPriorityAndArrivalTime(pcbs); System.out.print("就绪队列有: "); for(Pcb pcb: pcbs){ System.out.print(pcb.getPcbName() + " "); } //判断当前进程是否已完成 String flag = "Finish"; //就绪队列首进程添加到运行队列中 while(!flag.equals(pcbs.get(0).getPcbState())){ execpcbs.add(pcbs.get(0)); for(Pcb pcb: execpcbs){ System.out.println("执行队列有: " + pcb.getPcbName()); } System.out.println("进程"+pcbs.get(0).getPcbName()+"开始运行"); //运行时间+1,判断是否到达运行时间 isTimeToRunningTime(hasUsedTimeAdd1(pcbs.get(0)), pcbs, execpcbs); if(pcbs!=null && pcbs.size()>0){ execpcbs.remove(pcbs.get(0)); } break; } } } }3. Pcb类有了,方法类有了,最后肯定要来一个主类了,总要让程序有入口是吧。主类的工作是啥呢?首先它要提供程序入口main(),然后它要创建进程对象,调用方法类中的方法完成初始化,然后执行调度算法,再然后,好像没有然后了。我主类的工作做完了,剩下的不是他们干吗?
怎么调用就不用我说了吧。
我还是说一下吧。。。
JobRun.java
import java.util.ArrayList; import java.util.List; import java.util.Scanner; /** * @author GoldenRetriever */ public class JobRun { public static void main(String[] args) { System.out.println("******高优先权调度算法开始:******"); System.out.println("1.动态优先级算法(输入进程信息)。"); System.out.println("2.动态优先级算法(随机进程信息)。"); System.out.println("请输入你想要执行的算法:"); try (Scanner scanner = new Scanner(System.in)) { int x = scanner.nextInt(); switch (x) { case 1: dynamicPriorityInput(); break; case 2: dynamicPriorityRandomInput(); break; default: break; } } catch (Exception e) { System.out.println(e); } } /** * 进程信息初始化(随机) * 我想偷懒 */ private static void dynamicPriorityRandomInput() { Scanner sc = new Scanner(System.in); //输入作业队列 List<Pcb> pcbs = new ArrayList<>(); //执行作业队列 List<Pcb> execpcbs = new ArrayList<>(); do { //创建进程对象 Pcb pcb = new Pcb(); //初始化pcb对象然后赋给新对象 Pcb initPcb = DynamicPriority.initByRandom(pcb); //队列添加字符串 pcbs.add(initPcb); System.out.println("已完成一个进程信息初始化,是否继续:(是输入y,否输入n)"); } while (sc.nextLine().equalsIgnoreCase("y")); System.out.println("-----------------"); //确认初始化成功 for (Pcb pcb : pcbs) { System.out.println(pcb.toString()); } //执行调度算法,将就绪队列按照算法,插入到执行队列中 DynamicPriority.dispatchpcb(pcbs, execpcbs); System.out.println("-----------------"); } /** * 进程信息初始化(输入) * 不,你不想 */ private static void dynamicPriorityInput() { System.out.println("请输入进程的相关信息:(输入no代表结束)"); Scanner sc = new Scanner(System.in); //输入作业队列 List<Pcb> pcbs = new ArrayList<>(); //执行作业队列 List<Pcb> execpcbs = new ArrayList<>(); do { //创建进程对象 Pcb pcb = new Pcb(); //初始化pcb对象然后赋给新对象 Pcb initPcb = DynamicPriority.initByInput(pcb); //队列添加字符串 pcbs.add(initPcb); System.out.println("是否要继续输入作业相关信息:(是输入yes,否输入no)"); } while (sc.nextLine().equalsIgnoreCase("yes")); System.out.println("-----------------"); //确认初始化成功 for (Pcb pcb : pcbs) { System.out.println(pcb.toString()); } //执行调度算法,将就绪队列按照算法,插入到执行队列中 DynamicPriority.dispatchpcb(pcbs, execpcbs); System.out.println("-----------------"); } }我想偷懒 不,你不想
第一次在csdn上写文章,可能文章并不是很严谨,然后这个又是针对具体的实验而言,写的不好,或者文章中有任何不足希望指出,虚心接受,坚决不改,开玩笑哈。当然也感谢你能看到最后,这么长也不容易,Thanks。如果有任何能帮到你的地方,那就举个小爪爪,关注下呗,不定期更新哈,不说那么多,拜拜!
