- 
     目的与任务
 
 (1)目的:了解并掌握作业调度的功能,熟悉并掌握各种作业调度算法。
 
 (2)任务:模拟实现先来先服务或者短作业优先调度算法。
 
 (3)实验环境:安装eclipse 环境的Windows10 X64 操作系统。
- 
     内容、要求与安排
 
 (1)实验内容
 
 1.模拟实现FCFS/SJF调度。
 
 2.设置作业体:作业名,作业的到达时间,服务时间,作业状态(W——等待,R——运行,F——完成),作业间的链接指针;
 
 3.作业初始化:由用户输入作业名、服务时间、到达时间进行初始化,同时,初始化作业的状态为W。
 
 4.显示函数:在作业调度前、调度中和调度后进行显示。
 
 5.排序函数:对等待状态的作业按照调度算法排序(不同的调度算法排序方式不同),注意考虑到达时间。
 
 6.调度函数:每次从等待队列队首调度已到达的适合的作业执行,状态变化。当服务结束时,状态变为F。
 
 7.删除函数:撤销状态为F的作业。
- 
     实验设计与实施
 
 (1)优先级调度算法(first come first service FCFS)按作业到达系统的先后次序进行调度。该算法优先考虑在系统中等待时间最长的作业,而不考虑作业运行时间的长短。例如,有4个作业组成的一个作业流,在给出了作业的提交时间、运行时间后,经计算给出了作业的开始时间、完成时间、周转时间和带权周转时间。作业的状态可以是等待W(Wait)、运行R(Run)和完成F(Finish)三种状态之一。每个作业的最初状态总是等待W。各个等待的作业按照提交时刻的先后次序排队,总是首先调度等待队列中队首的作业。每个作业完成后要打印该作业的开始运行时刻、完成时刻、周转时间和带权周转时间,这一组作业完成后要计算并打印这组作业的平均周转时间、带权平均周转时间。FCFS调度算法的流程图如图1.1所示 :
 
   
图1.1
    (2)短作业优先调度(SJF)算法
    
    SJF(shortest job first)是以进程的运行时间长度作为优先级,进程运行时间越短,优先级越高。
    
    SJF算法的缺点
    
    1.必须预知进程的运行时间。即使是程序员也很难准确估计进程运行时间。如果估计过低,系统就可能按估计的时间终止进程的运行,但此时进程并未完成,故一般都会偏长估计。
    
    2.对长进程不利。长进程的周转时间会明显地增长。可怕的是,SJF算法完全忽视进程等待时间,可能使进程等待时间过长,出现饥饿现象。
    
    3.人机无法实现交互。
    
    4.完全未考虑进程的紧迫程度。不能保证紧迫性进程得到及时处理。
    
    SJF算法流程图如图1.2所示。
    
     
   
图1.2
    (3)实施
    
    以下定义的类分别实现对应的功能。
    
    伪代码如下:
    
    public static Process[] SJF(Process[] p){
    
    
    //短作业优先算法
    
    }
    
    public static void FCFS(Process[] p){
    
    
    //先来先服务算法
    
    }
    
    public static void InsertSort(Process[] array)
    
    {
    
    
    //插入排序
    
    }
    
    public static Process FindNextPro(List list,int now){
    
    
    //找出下一个处理的进程
    
    }
    
    public static void Out(Process[] p){
    
    
    //输出
    
    }
   
- 
     实验结果与分析
 
 (1)测试实例如表
 
 1.1所示:
 
 分钟(单位)
| 进程ID | 进程到达的时间 | 进程服务时间 | 
|---|---|---|
| A | 0 | 3 | 
| B | 1 | 13 | 
| C | 2 | 5 | 
| D | 3 | 4 | 
表1.1
    测试结果如图1.3所示:
    
     
   
图1.3
    (2)实验分析
    
    最高响应比是优先作业调度,既照顾了短作业,又照顾了作业到来的顺序,不会使长作业长期得不到运行,但是每次调度下一个作业前要计算剩余到来作业的响应比,增加了系统的开销。
   
先来先服务的作业调度的作业平均周转时间T=14.75分钟
最短作业优先服务作业调度的作业平均周转时间T=10.50分钟
1、对于4个不同批次作业,先来先服务的作业调度
    进程A,作业带权平均周转时间 W=1.00
    
    进程B,作业带权平均周转时间 W=1.15
    
    进程C,作业带权平均周转时间 W=3.80
    
    进程D,作业带权平均周转时间 W=5.50
   
可见,先来先服务的作业调度,对于进程A作业的效率最高。
2、对于4个不同批次作业,最短优先服务的作业调度
    进程A,作业带权平均周转时间 W=1.00
    
    进程B,作业带权平均周转时间 W=1.20
    
    进程C,作业带权平均周转时间 W=2.25
    
    进程D,作业带权平均周转时间 W=1.85
   
可见,最短优先服务的作业调度,对于进程A作业的效率最高。
FCFS算法是指进程调度时是从就绪的进程队列中选择一个最先进入该队列的进程,为之分配处理机,使之投入运行的一种调度算法。
SJF算法是指以作业的长短来计算优先级,作业越短,其优先级越高,越优先将他们调入内存运行。
FCFS有利于长作业,不利于短作业。
SJF有利于短作业,不利于长作业。
附上JAVA代码:
import java.text.DecimalFormat;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
 
public class experiment1 {
	public static void main(String[] args) {
		Scanner in= new Scanner(System.in); 
		
		System.out.println("请输入进程个数:");
		int n=in.nextInt();
		
		Process[] p=new Process[n];
		
		System.out.println("请输入每个进程的到达时间和服务时间和进程ID:");
		
		//初始化进程数据
		for(int i=0;i<n;i++){
			int arrTime=in.nextInt();
			int serTime=in.nextInt();
			String pid=in.nextLine();
			p[i]=new Process(arrTime, serTime,pid);
		}
		
		while(true){
			System.out.println("请选择进程调度算法,1:FCFS 2:SJF 其他键:quit");
			int select=in.nextInt();
			if(select==1){
				System.out.println("----------------您选择了FCFS-------------------");
				FCFS(p);
				Out(p);
				
			}
			else if(select==2){
				System.out.println("----------------您选择了SJF-------------------");
				Process[] processes=SJF(p);
				Out(processes);
			}
			else{
				break;
			}
		}
		
	}
	
	//输出
	public static void Out(Process[] p){
		DecimalFormat df = new DecimalFormat("#.00");   
		float sumWT=0;
		float sumWWT=0;
		float AverageWT;
		float AverageWWT;
		for(int i=0;i<p.length;i++){
			System.out.println("时刻"+p[i].startTime+": 进程"+p[i].pid+"开始运行,完成时间为:"+p[i].finishTime+",周转时间为:"+p[i].WholeTime+",带权周转时间为:"+df.format(p[i].weightWholeTime));
			sumWT+=p[i].WholeTime;
			sumWWT+=p[i].weightWholeTime;
		}
		AverageWT=sumWT/p.length;
		AverageWWT=sumWWT/p.length;
		
		System.out.println("平均周转时间为:"+df.format(AverageWT));
		System.out.println("平均带权周转时间为:"+df.format(AverageWWT));
		System.out.println("---------------------------------------------------------");
	}
	
	//找出下一个处理的进程
	public static Process FindNextPro(List<Process> list,int now){
		Process pro=list.get(0);
		int index=0;
		for(int i=1;i<list.size();i++){
			if(list.get(i).serviceTime<pro.serviceTime&&list.get(i).arrivalTime<=now){
				pro=list.get(i);
				index=i;
			}
		}
		list.remove(index);
		return pro;
	}
	
	//插入排序
	public static void InsertSort(Process[] array)
	{
	    int i, j;
	    int n = array.length;
	    Process target;
	    for (i = 1; i < n; i++)
	    {
	        j = i;
	        target = array[i]; 
	        while (j > 0 && target.arrivalTime < array[j - 1].arrivalTime)
	        {
	            array[j] = array[j - 1];
	            j--;
	        } 
	        array[j] = target;
	    }
	}
	
	//先来先服务算法
	public static void FCFS(Process[] p){
		
		//按到达时间对进程进行排序
		InsertSort(p);
				
		for(int i=0;i<p.length;i++){
			//计算完成时间
			if(i==0){
				p[i].finishTime=p[i].arrivalTime+p[i].serviceTime;
			}else{
				if(p[i].arrivalTime>p[i-1].finishTime){
					p[i].finishTime=p[i].arrivalTime+p[i].serviceTime;
					p[i].startTime=p[i].arrivalTime;
				}
				else{
					p[i].finishTime=p[i].serviceTime+p[i-1].finishTime;
					p[i].startTime=p[i-1].finishTime;
				}
			}
			
			//计算周转时间和带权周转时间
			p[i].WholeTime=p[i].finishTime-p[i].arrivalTime;
			p[i].weightWholeTime=(double)p[i].WholeTime/(double)p[i].serviceTime;
			
		}
	}
	
	//短作业优先算法
	public static Process[] SJF(Process[] p){
		
		//当前时间
		int now=0;
		//待处理list
		List<Process> list=new LinkedList<>();
		//结果list
		List<Process> res=new LinkedList<>();
		//按时间对进程进行排序
		InsertSort(p);
		
		//处理第一个进程
		p[0].finishTime=p[0].arrivalTime+p[0].serviceTime;
		p[0].WholeTime=p[0].finishTime-p[0].arrivalTime;
		p[0].weightWholeTime=p[0].WholeTime/p[0].serviceTime;
		res.add(p[0]);
		
		now=p[0].finishTime;
		
		//将剩余进程添加进待处理list
		for(int i=1;i<p.length;i++){
			list.add(p[i]);
		}
		
		while(list.size()!=0){
			Process next=FindNextPro(list, now);
			if(next.arrivalTime>now){
				next.finishTime=next.arrivalTime+next.serviceTime;
				next.startTime=next.arrivalTime;
			}else{
				next.finishTime=now+next.serviceTime;
				next.startTime=now;
			}
			now=next.finishTime;
			next.WholeTime=next.finishTime-next.arrivalTime;
			next.weightWholeTime=(double)next.WholeTime/(double)next.serviceTime;
			res.add(next);
		}	
			
		return res.toArray(new Process[0]);
		
	}
	
 
}
 
//进程的数据结构
class Process{
	public int arrivalTime;
	public int serviceTime;
	public int finishTime;
	public int startTime;
	public int WholeTime;
	public double weightWholeTime;
	public String pid;
	
	Process(int x,int y,String id){
		arrivalTime=x;
		serviceTime=y;
		pid=id;
	}
}
 
