一、实验目的:
编写并调试一个模拟的进程调度程序,以加深对进程的概念及进程调度算法的理解.
二、实验内容:
- 调试运行“短进程优先”调度算法,给出运行结果。
- 采用“短进程优先”调度算法对五个进程进行调度。每个进程有一个进程控制块( PCB)表示。进程控制块可以包含如下信息:进程名、到达时间、需要运行时间、已用CPU时间、进程状态等等。
- 每个进程的状态可以是就绪 W(Wait)、运行R(Run)、或完成F(Finish)三种状态之一。 每进行一次调度程序都打印一次运行进程、就绪队列、以及各个进程的 PCB,以便进行检查。重复以上过程,直到所要进程都完成为止。
三、实现思路:
- 自定义内部类PCB模拟进程控制块,每一个实例PCB对象代表一个进程,具备到达时间、服务时间、状态等属性。
- 先对用户输入的各进程按照到达时间初步排序,并在某进程运行的同时选择最先到达并且运行时间最短的进程作为下一个运行的进程。
- 每单位时间内输出当前处于运行状态的进程。进程运行结束后将状态更改为已完成并计算输出(带权)周转时间等指标。
四、主要的数据结构:
/**
* @Class 内部类PCB 模拟进程控制块
* @Description shortFirst
*/
private static class PCB implements Comparable<PCB> {
String id;
float reachTime; //到达时间
float needTime; //需要时间
float startTime; //开始时间
float finishTime;//结束时间
char state;
//重写比较器
public int compareTo( PCB b ) {
if( reachTime == b.reachTime )
return 0;
if( reachTime < b.reachTime )
return -1;
return 1;
}
}
五、程序流程图:
六、算法关键代码:
/**
* function: 找到下一个待运行进程
* 两种情况:
* 1.在lastTime时刻,选择已经到达且拥有最短运行时间的进程;
* 2.在lastTime时刻,没有进程到达,此时选择拥有最早到达时间的进程。
*/
private static int findNext( PCB[] arr, float lastTime ) {
int i, p = -1;
float minNeedTime = INF;
for( i = 0; i < arr.length; i++ ) {
if( arr[i].state == 'R' ) {
/* 数组arr已经按reachTime排序,当出现
arr[i].reachTime>lastTime时,说明在lastTime时刻无进程到达,终止循环。*/
if( arr[i].reachTime > lastTime )
break;
if( arr[i].needTime < minNeedTime ){
p = i;
minNeedTime = arr[i].needTime;
}
}
}
if( p != -1 )
return p;
return i;
}
/**
* function: main方法
*/
public static void main( String[] args ) {
Scanner sc = new Scanner( System.in );
System.out.println("-----3118004950 柴政 软工一班 FIFO-----\n");
/*获取到进程数组*/
System.out.print( "请输入进程数:" );
int num = sc.nextInt();
PCB[] arr = new PCB[num];
System.out.println( "请依次输入进程ID,进程到达时间,进程运行时间:" );
for( int i = 0; i < num; i++ ) {
arr[i] = new PCB();
arr[i].id = sc.next();
arr[i].reachTime = sc.nextFloat();
arr[i].needTime = sc.nextFloat();
arr[i].state = 'R';
}
// 使进程按reachTime(到达时间)排序。
Arrays.sort(arr);
/*
* 输出具体运行过程:
* 此时设每个进程处于
* 1.就绪R(Ready);
* 2.运行E(Excecuting);
* 3.完成F(Finish).
* 三种状态之一,并假设起始状态都是就绪状态。
*/
int p = 0;
int cnt = 0;
for(float time = arr[p].reachTime; cnt < num; time+=0.5 ){
if( arr[p].reachTime <= time && arr[p].state == 'R' ){
// 记录开始时间
arr[p].startTime = time;
arr[p].state = 'E';
System.out.format( "在%.2f时刻: ", time );
System.out.format( "进程%s开始运行\n", arr[p].id );
}else if( time-arr[p].startTime < arr[p].needTime && arr[p].state == 'E'){
System.out.format( "在%.2f时刻: ", time );
System.out.format( "进程%s正在运行\n", arr[p].id );
}else if( time-arr[p].startTime >= arr[p].needTime && arr[p].state == 'E'){
arr[p].finishTime = time; // 记录完成时间
arr[p].state = 'F';
System.out.format( "在%.2f时刻: ", time );
System.out.format( "进程%s完成运行\n\n", arr[p].id );
//找到下一个要执行的进程。
p = findNext( arr, time );
//用于判断结束时刻是否将有进程运行。
time -= 0.5;
//已经完成cnt个进程。
cnt++;
}
}
/*输出测试结果*/
//略
} //EndOf Function main()
七、运行测试:
测试数据:
八、总结:
短作业优先算法的模拟并不难,重点是理解其核心要义,并采用熟悉的数据结构和方法去实现其运行流程。核心的目标在于实现找到在某进程正在运行的时间内到达且服务时间最短的进程作为下一个运行的进程,并做好进程状态的标记,最后按照公式计算出各进程的时间指标即可。