常见的磁盘调度算法有:
1.FCFS:先来先服务算法;
2.SSTF:最短寻道时间算法;
3.SCAN:扫描算法(也叫电梯调度算法);
4.CSCAN:循环扫描算法
算法的详细介绍:
FCFS:算法思想非常简单,就是不论初始磁头在什么位置,都是按照服务队列的先后顺序依次处理进程,可以类比队列的先进先出。优点是进程处理起来非常简单,但缺点显而易见,就是平均寻道长度会很长。
Java实现:
public class fcfs { Scanner x=new Scanner(System.in); public int[] position; public int num; public fcfs() { System.out.println("Enter the number of process:"); num=x.nextInt(); position=new int[num]; } public void input() { int i=0; for(i=0;i<num;i++) position[i]=x.nextInt(); } public void algo() { int i=1; for(i=1;i<=num;i++) System.out.println("Process Accessed "+i+" at "+position[i-1]); } }
SSTF:最短寻道时间算法,算法本质是贪心,已知磁头的初始位置,则最先被处理就是距离磁头位置最近的进程,处理完成后再处理距离当前磁道最近的进程,直到所有的进程被处理。该算法的优点是平均寻道长度会大大减少,缺点是距离初始磁头较远的服务长期得不到处理,产生“饥饿”现象。具体的思路是:通过循环寻找与初始磁头最近的进程,将进程处理,然后将该进程标记为-1,将初始磁头移动到该进程所在的磁道。然后依次类推,标记为-1的进程不再参与,知道所有的进程都被标记为-1,磁盘调度完成。
Java实现
public class sstfAlg{ int num; int[][] position; int size; int initPos; int[] sequenceOfProcess ;//存储访问序列 int[] sequenceOfNumber; Scanner sc = new Scanner(System.in); public sstfAlg(int a,int b,int c){ //a means the amount of process //b means the inital of position //c means the size of disk num = a; position = new int[a][2]; sequenceOfProcess = new int[a]; sequenceOfNumber = new int[a]; initPos = b; size = c; } public void input(){ System.out.println("input the number of process:"); for(int i=0;i<num;i++){ position[i][0] = sc.nextInt(); position[i][1] = i+1; } } public void myAlg(){ int nearest = 10000; int index = 0 ; int initPos1 = initPos; //复制一个数组用来寻找访问序列 int[][] position1 = new int[num][2]; for(int i=0 ;i<num;i++){ position1[i][0] = position[i][0]; position1[i][1] = i+1; } //寻找磁头访问的序列 for(int i=0;i<num;i++){ for(int j=0;j<num;j++){ if(position1[j][0]!=-1){ if(Math.abs(initPos1 - nearest)>Math.abs(position1[j][0]-initPos1)){ nearest = position1[j][0]; index = j; } } } sequenceOfProcess[i] = nearest; sequenceOfNumber[i] = index+1; position1[index][0] = -1;//-1表示此位置的进程已经放在了访问序列,不在进行查询 initPos1 = nearest; nearest = 10000; } for(int i=0;i<num;i++){ System.out.println("进程"+sequenceOfNumber[i]+"在磁道"+sequenceOfProcess[i]+"完成"); } }
SCAN:磁头仅沿一个方向进行扫描,在扫描途中完成所有没有完成的请求,直到磁头到达磁盘在这个方向上的最后一个磁道或者这个方向上最后一个请求所在的磁道。利用数组存储进程和磁道编号,依据给定的初始磁头,先找到初始磁头在哪两个进程之间,然后向内扫描。当磁头扫描到磁盘最内层即磁道0且进程还没有全部被处理,磁头开始向外扫描,直到所有的进程都完成。
Java实现
class scanAlgo{ Scanner sc = new Scanner(System.in); int num; //进程数量 int[] position1; int initPos; //磁头初始位置 public scanAlgo(){ System.out.println("input the amount of process:"); num = sc.nextInt(); position1 = new int[num+1]; System.out.println("input the initial position:"); initPos = sc.nextInt(); } public void input(){ System.out.println("input the number of process:"); for(int i=0;i<num;i++){ position1[i] = sc.nextInt(); //记录进程所在的磁道号 } } public void adjust(){ //按照磁道编号将进程排序,就是一个冒泡排序 for(int i=0;i<num;i++){ for(int j=1;j<num-i;j++){ if(position1[j-1] > position1[j]){ int temp = position1[j]; position1[j] = position1[j-1]; position1[j-1] = temp; } } } } public void algo(){ //寻找磁头初始位置在哪两个进程之间 input(); adjust(); int init; for(init=0;init<num-1;init++){ if(position1[init] <= initPos && position1[init+1] > initPos) break; //此时得到的init值就是磁头初始位置 } int start = init; //磁头先向里扫描 for(int i=start;i>=0;i--){ System.out.println("The First Time Scan:"+"Process"+position[i][1]+"At Position"+position[i][0]+"Completed"); } } //磁头开始从初始位置向外扫描 if(position1[init+1]!=0){ System.out.println("This Is the Track 0"); } for(int i=start+1;i<num;i++){ System.out.println("The Second Time Scan:"+"Process"+position[i][1]+"At Position"+position[i][0]+"Completed"); } } } }
CSCAN:在磁盘扫描算法的基础上改变磁头的扫描路径:扫描到最内层之后从最外层向内继续扫描,即扫描方向一致。该算法的思路与扫描算法基本一致,也使用二维数组进行进程编号和进程所在磁道号的存储,算法的不同之处在于当磁头扫描到磁盘的最内层时,磁头跳转到磁盘最外层重新向内扫描,这样就可以有效的避免将已经扫描过的磁道重新扫描一次,降低了平均寻到距离。
Java实现
class cscanAlg{ Scanner sc = new Scanner(System.in); int num; int[][] position ; int initPos; int size; public cscanAlg (){ System.out.println("input the amount of process:"); num = sc.nextInt(); position = new int[num+1][2]; System.out.println("input the initial position :"); initPos = sc.nextInt(); System.out.println("input the size of Disk:"); size = sc.nextInt(); } public void input(){ System.out.println("input the number of process:"); for(int i = 0;i<num;i++ ){ position[i][0] = sc.nextInt(); position[i][1] = i+1; } } public void adjust(){//调整数组中进程的记录顺序 for(int i=0;i<num;i++){ for(int j=1;j<num-i;j++){ if(position[j-1][0]>position[j][0]){ int temp1 = position[j][0]; int temp2 = position[j][1]; position[j][0] = position[j-1][0]; position[j][1] = position[j-1][1]; position[j-1][0] = temp1; position[j-1][1] = temp2; } } } } public void algo(){ input(); adjust(); int init; for(init = 0;init<num-1;init++){ if(position[init][0]<initPos && position[init+1][0]>=initPos){ break; } } int start = init; System.out.println("第一次扫描:"); for(int i=start;i>=0;i--){ System.out.println("第一次扫描:"+"进程"+position[i][1]+"在磁道"+position[i][0]+"完成"); } if(position[init+1][0]!=0){ System.out.println("磁头已经扫描到磁盘最内层:0"); } if(position[num-1][0]!=size){ System.out.println("磁头已经移到磁盘最外层:"+size); } System.out.println("第二次扫描:"); for(int i=num-1;i>start;i--){ System.out.println("第二次扫描:"+"进程"+position[i][1]+"在磁道"+position[i][0]+"完成"); } } }
为了直观的感受一下各种算法的差别,我选了大概500个进程处理来比较它们的时间和平均寻道长度(现实中肯定不会有这么多的待处理进程,不然炸了,只是为了比较),通过画折线图的方法进程比较,画折线图的实现过程在前面的文章中已经记录过了,所以直接上结果: