一、原理及说明
操作系统的任务之一就是有效地使用硬件。对磁盘驱动器,满足这一要求意味着要有较快的访问速度和较宽的磁盘宽带。磁盘宽带是指所传递的总字节数除以从服务请求开始到最后传递结束时的总时间。访问时间有寻道时间和旋转延迟两个主要部分。寻道时间是磁臂将磁头移动到包含目标扇区的柱面的时间。旋转延迟是磁盘需要将目标扇区转动到磁头下的时间。通常,最小寻道时间可以用最少寻道距离来表示。最常用的磁盘调度算法有以下几种:
1.先来先服务(FCFS)算法
根据进程请求访问磁盘的先后次序进行调度。算法的实现简单、公平;缺点:效率不高,相临两次请求可能会造成最内到最外的柱面寻道,使磁头反复移动,增加了服务时间,对机械也不利。
2.最短寻道时间优先(SSTF)算法
优先选择距当前磁头最近的访问请求进行服务,主要考虑寻道优先。优点:改善了磁盘平均服务时间;缺点:造成某些访问请求长期等待得不到服务。
3.扫描(SCAN)算法
当设备无访问请求时,磁头不动;当有访问请求时,磁头按一个方向移动,在移动过程中对遇到的访问请求进行服务,然后判断该方向上是否还有访问请求,如果有则继续扫描;否则改变移动方向,并为经过的访问请求服务,如此反复。克服了最短寻道优先的缺点,既考虑了距离,同时又考虑了方向。
4.循环扫描(C-SCAN)算法
总是从0号柱面开始向里扫描,按照各自所要访问的柱面位置的次序去选择访问者,移动臂到达最后一个柱面后,立即带动读写磁头快速返回到最小的需要方面的柱面,返回时不为任何的等待访问者服务,返回后可再次进行扫描。
二、例题
现有8个进程先后提出的磁盘I/O请求 :98 138 37 122 14 124 65 67,当前磁头位置为53号磁道,磁头向内移动。分别采用FCFS算法、SSTF算法、SCAN算法以及C-SCAN算法,画出磁头移动的轨迹,计算平均寻道长度。
代码:
FCFS算法
import java.util.Scanner;
public class FCFS
{
Scanner scan = new Scanner(System.in);
int[] req;
int num;
int[] move;
void input()
{
System.out.print("请输入进程数:");
num = scan.nextInt();
req = new int[num];
move = new int[num];
for(int i = 0; i < num; i++)
{
System.out.print("进程" + (i + 1) + "访问的磁道号:");
req[i] = scan.nextInt();
}
System.out.println();
}
void search()
{
System.out.print("请输入开始的磁道号:");
int start = scan.nextInt();
System.out.println("\n-------从" + start + "号磁道开始-------\n");
for(int i = 0; i < num; i++)
{
move[i] = Math.abs(start - req[i]);
start = req[i];
}
}
void show()
{
System.out.println("被访问的\t\t移动距离\n下一个磁道号\t(磁道数)\n");
for(int i = 0; i < num; i++)
{
System.out.println(req[i] + "\t\t" + move[i]);
}
double sum = 0;
for(int i : move)
{
sum += i;
}
System.out.println("平均寻道长度:" + sum / num);
}
FCFS()
{
System.out.println("----------先来先服务----------");
}
public static void main(String[] args)
{
FCFS fcfs = new FCFS();
fcfs.input();
fcfs.search();
fcfs.show();
}
}
SSTF算法
import java.util.List;
import java.util.Scanner;
//最短寻道时间优先
public class SSTF{
private int visit[];
private int nearIndex=0;
public int[] sstf(int queue[],int start){
int nearNum=9999;
visit=new int[queue.length];
for(int i=0;i<queue.length;i++){
for(int j=0;j<queue.length;j++){
if(queue[j]!=-1){
if(Math.abs(nearNum-start)>Math.abs(queue[j]-start)){
nearNum=queue[j];
nearIndex=j;
}
}
}
visit[i]=nearNum;
queue[nearIndex]=-1;
start=nearNum;
nearNum=9999;
}
return visit;
}
public void print(int visit[],int start){
double sum=0;
System.out.print("访问序列:");
for(int i=0;i<visit.length;i++){
System.out.print(visit[i]+" ");
sum=Math.abs(visit[i]-start)+sum;
start=visit[i];
}
System.out.println();
System.out.println("经过的磁道总数:"+sum);
System.out.println("平均寻道长度:"+sum/visit.length);
}
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
System.out.println("请输入磁盘请求序列长度:");
int a=sc.nextInt();
System.out.println("请输入磁盘请求访问序列:");
int[] queue=new int[a];
for(int i=0;i<a;i++){
queue[i]=sc.nextInt();
}
SSTF sstf=new SSTF();
System.out.println("请输入读写头起始位置:");
int start=sc.nextInt();
sstf.print(sstf.sstf(queue, start),start);
}
}
SCAN算法
import java.util.List;
import java.util.Scanner;
public class SCAN{
private int visit[];
private int nearIndex=0;
public int[] scan(int queue[],int start,int direction){
int nearNum=9999;
int index=0;
visit=new int[queue.length];
for(int i=0;i<queue.length;i++){
index=-1;
for(int j=0;j<queue.length;j++){
if(queue[j]!=-1){
if((direction==1)&&(queue[j]>start)&&(Math.abs(nearNum-start)>Math.abs(queue[j]-start))){
nearNum=queue[j];
nearIndex=j;
index=0;
}
else if((direction==0)&&(queue[j]<start)&&(Math.abs(nearNum-start)>Math.abs(queue[j]-start))){
nearNum=queue[j];
nearIndex=j;
index=0;
}
}
}
if((direction==1)&&(index==-1)){
direction=0;
i=i-1;
}
else if((direction==0)&&(index==-1)){
direction=1;
i=i-1;
}
if(index==0){
visit[i]=nearNum;
queue[nearIndex]=-1;
start=nearNum;
nearNum=9999;
}
}
return visit;
}
public void print(int visit[],int start){
double sum=0;
System.out.print("访问序列:");
for(int i=0;i<visit.length;i++){
System.out.print(visit[i]+" ");
sum=Math.abs(visit[i]-start)+sum;
start=visit[i];
}
System.out.println();
System.out.println("经过的磁道总数:"+sum);
System.out.println("平均寻道长度:"+sum/visit.length);
}
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
System.out.println("请输入磁盘请求序列长度:");
int a=sc.nextInt();
System.out.println("请输入磁盘请求访问序列:");
int[] queue=new int[a];
for(int i=0;i<a;i++){
queue[i]=sc.nextInt();
}
SCAN scan=new SCAN();
System.out.println("请输入读写头起始位置:");
int start=sc.nextInt();
System.out.println("磁道增加的方向:(0向外移动,1向内移动)");
int direction=sc.nextInt();
scan.print(scan.scan(queue, start,direction),start);
}
}
C-SCAN算法
import java.util.Scanner;
public class CSCAN
{
Scanner scan = new Scanner(System.in);
int[] req;
int num;
int[] move;
int[] visit;
void input()
{
System.out.print("请输入进程数:");
num = scan.nextInt();
req = new int[num];
move = new int[num];
visit = new int[num];
for (int i = 0; i < num; i++)
{
System.out.print("进程" + (i + 1) + "访问的磁道号:");
req[i] = scan.nextInt();
}
System.out.println();
}
void search()
{
System.out.print("请输入开始的磁道号:");
int start = scan.nextInt();
System.out.println("\n从" + start + "号磁道开始,向内移动\n");
bubbleSort(req);
int firstIndex = -1;
for (int i = 0; i < num; i++)
{
if (start > req[i])
continue;
firstIndex = i;
break;
}
if (firstIndex != -1)
{
int index = firstIndex;
for (int i = 0; i < num - index; i++)
{
visit[i] = req[firstIndex];
move[i] = req[firstIndex] - start;
start = visit[i];
firstIndex++;
}
for (int i = 0, pos = num - index; i < index; i++, pos++)
{
visit[pos] = req[i];
move[pos] = Math.abs(req[i] - start);
start = visit[pos];
}
} else
{
for (int i = 0; i < num; i++)
{
visit[i] = req[i];
move[i] = Math.abs(req[i] - start);
start = visit[i];
}
}
}
void bubbleSort(int arr[])
{
for (int i = 0; i < arr.length - 1; i++)
{
for (int j = 0; j < arr.length - 1 - i; j++)
{
if (arr[j] > arr[j + 1])
{
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
void show()
{
System.out.println("被访问的\t\t移动距离\n下一个磁道号\t(磁道数)\n");
for (int i = 0; i < num; i++)
{
System.out.println(visit[i] + "\t\t" + move[i]);
}
double sum = 0;
for (int i : move)
{
sum += i;
}
System.out.println("平均寻道长度:" + sum / num);
}
CSCAN()
{
System.out.println("--------循环扫描算法--------");
}
public static void main(String[] args)
{
CSCAN c = new CSCAN();
c.input();
c.search();
c.show();
}
}