说明:用高级语言编写和调试一个进程调度程序,以加深对进程的概念及进程调度算法的理解。
(1)进程的状态
(2)进程的结构——PCB
进程都是由一系列操作(动作)所组成,通过这些操作来完成其任务。因此,不同的进程,其内部操作也不相同。在操作系统中,描述一个进程除了需要程序和私有数据之外,最主要的是需要一个与动态过程相联系的数据结构,该数据结构用来描述进程的外部特性(名字、状态等)以及与其它进程的联系(通信关系)等信息,该数据结构称为进程控制块(PCB,Process Control Block)。
进程控制块PCB与进程一一对应,PCB中记录了系统所需的全部信息、用于描述进程情况所需的全部信息和控制进程运行所需的全部信息。因此,系统可以通过进程的PCB来对进程进行管理。
(3)算法
设计一个有 N个进程共行的进程调度程序。
进程调度算法:采用最高优先数优先的调度算法(即把处理机分配给优先数最高的进程)和先来先服务算法。每个进程有一个进程控制块( PCB)表示。进程控制块可以包含如下信息:进程名、优先数、到达时间、需要运行时间、已用CPU时间、进程状态等等。 进程的优先数及需要的运行时间可以事先人为地指定(也可以由随机数产生)。进程的到达时间为进程输入的时间。进程的运行时间以时间片为单位进行计算。每个进程的状态可以是就绪 W(Wait)、运行R(Run)、或完成F(Finish)三种状态之一。就绪进程获得 CPU后都只能运行一个时间片。用已占用CPU时间加1来表示。如果运行一个时间片后,进程的已占用 CPU时间已达到所需要的运行时间,则撤消该进程,如果运行一个时间片后进程的已占用CPU时间还未达所需要的运行时间,也就是进程还需要继续运行,此时应将进程的优先数减1(即降低一级),然后把它插入就绪队列等待CPU。每进行一次调度程序都打印一次运行进程、就绪队列、以及各个进程的 PCB,以便进行检查。
重复以上过程,直到所要进程都完成为止。
调度算法的流程图如下 :
主函数Main():
主方法类,主要是为了给所有类进行统一的调用,使程序有一定的顺序感,并且按顺序执行能够得到正确的答案。主方法中,需要首先对工作类进行初始化数据,模拟进程的初始化;再对进程进行模拟程序执行运行时间,然后执行调度算法,将输入队列进程按照高优先权调度算法,插入到执行队列中(使用的是静态优先权调度),计算执行队列中各个的进程的开始时间,结束时间,周转时间等等;打印输出执行队列中的工作信息。
import java.util.Scanner;
import java.util.List;
import java.util.ArrayList;
/**
* 进程调度算法实现类
* @author Alice
*
*/
public class Main {
@SuppressWarnings("Do you like what you see?")
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("这是一个高优先权调度算法,马上开始:");
System.out.println("请先输入作业的相关信息:(输入no代表结束)");
//输入作业队列
List<PCB> pcbs = new ArrayList<>();
//这是执行队列
List<PCB> execpcbs = new ArrayList<>();
//信息初始化
do {
PCB P = new PCB();
PCB initP = DynamicJobFirstUtil.init(P);
pcbs.add(initP);
System.out.println("是否继续输入作业信息:( yes or no)");
}while (scanner.nextLine().equalsIgnoreCase("yes"));
System.out.println("............................");
//初始化完场
for (PCB pcb : pcbs){
System.out.println(pcb.toString());
}
//执行调度算法,将输入队列作业按照算法,插入到执行队列中
execpcbs = DynamicJobFirstUtil.dispatchpcb(pcbs, execpcbs);
System.out.println("............................");
//求出周转时间和平均周转时间并记录在每一个作业实体中
DynamicJobFirstUtil.turnRoundTime(execpcbs);
for (PCB P : execpcbs){
System.out.println(P.toString());
}
System.out.println("............................");
DynamicJobFirstUtil.showTime(execpcbs);
}
}
PCB类:
封装进程的相关属性和方法。主要定义有关进程中封装的属性,比如进程名称,进程服务时间,进程到达时间,进程开始时间,进程优先级,进程状态,进程结束时间,进程周转时间,进程平均周转时间等,以及其get和set方法。
public class PCB {
//进程名
private String pcbName;
//进程到达时间
private int pcbArrivalTime;
//进程服务时间
private int pcbServiceTime;
//进程初始优先权限
private int firstNum;
//进程状态
private char pcbState;
//进程间的链接指针
private PCB nextPCB;
//进程开始时间
private int pcbStartTime;
//进程完成时间
private int pcbOverTime;
//进程周转时间
private int pcbRoundTime;
//进程带权周转时间
private double pcbAvgRoundTime;
public String getPcbName(){
return pcbName;
}
public int getPcbArrivalTime(){
return pcbArrivalTime;
}
public int getPcbServiceTime() {
return pcbServiceTime;
}
public int getFirstNum() {
return firstNum;
}
public char getPcbState() {
return pcbState;
}
public PCB getNextPCB() {
return nextPCB;
}
public int getPcbStartTime() {
return pcbStartTime;
}
public int getPcbOverTime() {
return pcbOverTime;
}
public int getPcbRoundTime() {
return pcbRoundTime;
}
public double getPcbAvgRoundTime() {
return pcbAvgRoundTime;
}
public void setPcbName(String pcbName){
this.pcbName = pcbName;
}
public void setPcbArrivalTime(int pcbArrivalTime) {
this.pcbArrivalTime = pcbArrivalTime;
}
public void setPcbServiceTime(int pcbServiceTime) {
this.pcbServiceTime = pcbServiceTime;
}
public void setFirstNum(int firstNum) {
this.firstNum = firstNum;
}
public void setPcbState(char pcbState) {
this.pcbState = pcbState;
}
public void setNextPCB(PCB nextPCB) {
this.nextPCB = nextPCB;
}
public void setPcbStartTime(int pcbStartTime) {
this.pcbStartTime = pcbStartTime;
}
public void setPcbOverTime(int pcbOverTime) {
this.pcbOverTime = pcbOverTime;
}
public void setPcbRoundTime(int pcbRoundTime) {
this.pcbRoundTime = pcbRoundTime;
}
public void setPcbAvgRoundTime(double pcbAvgRoundTime) {
this.pcbAvgRoundTime = pcbAvgRoundTime;
}
@Override
public String toString() {
return "PCB{" +
"pcbName='" + pcbName + '\'' +
", pcbArrivalTime=" + pcbArrivalTime +
", pcbServiceTime=" + pcbServiceTime +
", firstNum=" + firstNum +
", pcbState=" + pcbState +
", nextPCB=" + nextPCB +
", pcbStartTime=" + pcbStartTime +
", pcbOverTime=" + pcbOverTime +
", pcbRoundTime=" + pcbRoundTime +
", pcbAvgRoundTime=" + pcbAvgRoundTime +
'}';
}
}
动态高优先度算法工具类DynamicJobFirstUtil():
调度算法的工具类,方法有
1.进程初始化 init()
2.按照服务时间去排序 sortByServerTime()(这里写出来没有用到)
3.按照到达时间去排序 sortByArrivalTime()
4. 先按照优先度排序,优先度相同的按照到达时间去排序 sortByStateAndArrivalTime()。
4.调度算法函数,最终将需要按顺序执行的进程放入execJobs中dispatchJob()。
5.求出周转时间,平均周转时间等其他信息 turnRoundTime()。
import java.text.SimpleDateFormat;
import java.util.*;
/**
* 动态高优先权优先调度算法工具类
* @author Alice
*
*/
public class DynamicJobFirstUtil {
private static SimpleDateFormat tm= new SimpleDateFormat("HH:mm:ss");
//进程初始化
@SuppressWarnings("Do you like what you see?")
public static PCB init(PCB pcb){
Scanner scanner = new Scanner(System.in);
System.out.println("请输入进程名称:如(进程1)");
pcb.setPcbName(scanner.nextLine());
System.out.println("请输入进程到达时间:如(1)");
pcb.setPcbArrivalTime(scanner.nextInt());
System.out.println("请输入进程服务时间:如(3)");
pcb.setPcbServiceTime(scanner.nextInt());
System.out.println("请输入进程初始优先权:如(1)");
pcb.setFirstNum(scanner.nextInt());
pcb.setPcbState('w');
return pcb;
}
//按照服务时间排序
public static void sortBySeverTime(List<PCB> pcbs){
//使用Collections工具类中的自定义条件排序方法
Collections.sort(pcbs, new Comparator<PCB>() {
@Override
public int compare(PCB pcb1, PCB pcb2) {
return (int) ( pcb1.getPcbServiceTime() - pcb2.getPcbServiceTime());
}
});
}
//按照到达时间排序
public static void sortByArrivalTime(List<PCB> pcbs){
//使用Collections工具类中的自定义条件排序方法
Collections.sort(pcbs, new Comparator<PCB>() {
@Override
public int compare(PCB pcb1, PCB pcb2) {
return (int) (pcb1.getPcbArrivalTime() - pcb2.getPcbArrivalTime());
}
});
}
//按照优先度排序,优先度相同的按照到达时间去排序
public static void sortByStateAndArrivalTime(List<PCB> pcbs){
//使用Collections工具类中的自定义条件排序方法
Collections.sort(pcbs, new Comparator<PCB>() {
@Override
public int compare(PCB pcb1, PCB pcb2) {
int cr = 0;
//首先按照优先级排降序
int a = pcb1.getFirstNum() - pcb2.getFirstNum();
if (a != 0){
cr = (a < 0) ? 3 : -1;
}else{
//然后按照到达时间排升序
a = pcb1.getPcbArrivalTime() - pcb2.getPcbArrivalTime();
if (a != 0){
cr = (a > 0) ? 2 : -2;
}
}
return cr;
}
});
}
/*调度算法函数,最终将需要按顺序执行的进程放入execpcbs中
pcbs,输入队列,execpcbs,执行队列*/
public static List<PCB> dispatchpcb(List<PCB> pcbs, List<PCB> execpcbs){
//中间队列,用于暂时存储输入队列中挑选出的进程
List<PCB> tempP = new ArrayList<>();
//CPU无工作的时候,给第一个到达的进程服务,结束时间到达的进程在执行
DynamicJobFirstUtil.sortByArrivalTime(pcbs);
execpcbs.add(pcbs.get(0));
pcbs.remove(pcbs.get(0));
//将输入队列中的进程一个一个的移动到执行队列
while (pcbs.size()>0){
//execpcbs队列的最后一个execpcb的结束时间
PCB exepcb = execpcbs.get((execpcbs.size() - 1));
int endTime = exepcb.getPcbArrivalTime() + exepcb.getPcbServiceTime();
//使用迭代器,便于输入队列的删除,避免出错
Iterator<PCB> iterator = pcbs.iterator();
//判断迭代
while (iterator.hasNext()){
PCB P = iterator.next();
//将执行队列中的结束时间大于输入队列到达时间的所有进程移动到执行队列
if (endTime >= P.getPcbArrivalTime()){
tempP.add(P);
iterator.remove();
}
}
//如果遍历之后,执行队列的结束时间还没有到达,则按照到达时间排序得到第一个
if (tempP == null){
DynamicJobFirstUtil.sortByArrivalTime(pcbs);
execpcbs.add(pcbs.get(0));
pcbs.remove(pcbs.get(0));
}
//按照服务时间长短进行排序,以免下面移动到执行队列的进程顺序出错
DynamicJobFirstUtil.sortByStateAndArrivalTime(tempP);
execpcbs.addAll(tempP);
tempP.clear();
}
for (PCB pcb : execpcbs){
pcb.setPcbState('r');
}
return execpcbs;
}
//求出周转时间,平均周转时间等其他信息
public static void turnRoundTime(List<PCB> pcbs){
//第一个的到达时间
int temp = pcbs.get(0).getPcbArrivalTime();
for (PCB pcb : pcbs){
//如果前一个进程的结束时间小鱼当前进程的到达时间
if (temp < pcb.getPcbArrivalTime()){
temp = pcb.getPcbArrivalTime();
}
//设置进程的开始时间,前一个的结束时间等于本次的开始时间
pcb.setPcbStartTime(temp);
//得到每个进程的服务时间
int serviceTime = pcb.getPcbServiceTime();
temp+=serviceTime;
//结束时间等于开始时间加服务时间
pcb.setPcbOverTime(temp);
//周转时间等于结束时间减去到达时间
int turnRound = temp-pcb.getPcbArrivalTime();
pcb.setPcbRoundTime(turnRound);
//带权周转时间等于周转时间除以服务时间
pcb.setPcbAvgRoundTime((1.0*turnRound)/serviceTime);
}
}
//输出进程运行时间
public static void showTime(List<PCB> pcbs){
System.out.println("进程名称\t\t到达时间\t\t服务时间\t\t开始时间\t\t优先级\t\t状态\t\t结束时间\t\t周转时间\t\t带权周转时间");
double turnRound = 0.0;
double avgTurnRound = 0.0;
for (PCB pcb : pcbs){
System.out.println(pcb.getPcbName()+"\t\t\t"+pcb.getPcbArrivalTime()+"\t\t\t"+pcb.getPcbServiceTime()
+"\t\t\t"+pcb.getPcbStartTime()+"\t\t\t"+pcb.getFirstNum()+"\t\t\t"+pcb.getPcbState()+"\t\t\t"+pcb.getPcbOverTime()+"\t\t\t"+pcb.getPcbRoundTime()
+"\t\t\t"+pcb.getPcbAvgRoundTime());
turnRound+=pcb.getPcbRoundTime();
avgTurnRound+=pcb.getPcbAvgRoundTime();
}
System.out.println(pcbs.size()+"个进程的平均周转时间为:"+String.format("%g %n",(1.0*turnRound)/pcbs.size()));
System.out.println(pcbs.size()+"个进程的平均带权周转时间为:"+String.format("%g %n",(1.0*avgTurnRound)/pcbs.size()));
}
}