算法导入
最近在学操作系统,老师的第一个实验要求——实现动态优先级进程调度算法。在度娘上也搜到了些,借鉴了一位大佬的设计思想,用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。如果有任何能帮到你的地方,那就举个小爪爪,关注下呗,不定期更新哈,不说那么多,拜拜!