本文已参与「新人创作礼」活动,一起开启掘金创作之路。
实验二 磁盘调度
前言
-
参考教材《操作系统 第四版》汤小丹
-
因为实验要求为了更好地模拟和评价算法的性能,随机产生需寻道的磁道序列,以磁道序列的首磁道为磁头的当前位置;在SCAN算法中,允许用户指定当前寻道方向;随机产生数据不方便对比,所以做了两份代码(一种随机产生磁道序列以磁道序列的首磁道为磁头的当前位置(这里命名为A)即实验内容,一种自定义磁道序列自定义磁头位置(这里命名为B)),完整代码放在文末了,方便对比
-
SCAN算法做出了两种方法,分别写在了固定磁头位置和自定义磁头位置
-
虽然只做了三种,循环算法大同小异,搞懂前三个,其它算法很好编写
实验目的
编程模拟实现磁盘调度的常用算法或调试分析相关磁盘调度程序,加深对磁盘调度常用算法的理解和实现技巧
实验内容
1.自定义磁盘调度相关的数据结构
2.依据先来先服务算法(FCFS)、最短寻道优先算法(SSTF)、扫描(SCAN,也称电梯)算法的原理,编写对应函数,模拟系统的磁盘调度服务;
3.为了更好地模拟和评价算法的性能,随机产生需寻道的磁道序列,以磁道序列的首磁道为磁头的当前位置;在SCAN算法中,允许用户指定当前寻道方向;
4.统计以上算法总寻道次数和平均寻道距离;
比较/分析以上算法的寻道性能,并作出自己的评价
实验步骤
冒泡排序
先写一个冒泡排序,在后面调用会使用到
// 冒泡排序(从小到大)
public static void SortA(int[] list){
for (int i = 0; i < list.length - 1; i++) {
for (int j = 0; j < list.length - 1 - i; j++) {
if (list[j] > list[j + 1]) {
int temp = list[j];
list[j] = list[j + 1];
list[j + 1] = temp;
}
}
}
}
// 冒泡排序(从大到小)
public static void SortB(int[] list) {
for (int i = 0; i < list.length - 1; i++) {
for (int j = 0; j < list.length - 1 - i; j++) {
if (list[j] < list[j + 1]) {
int temp = list[j];
list[j] = list[j + 1];
list[j + 1] = temp;
}
}
}
}
先来先服务FCFS
A
// 先来先服务FCSFS,即根据磁盘访问的先后次序进行调度,遍历list数组即可,所以不做赘述
private static void FCFS(int[] list) {
System.out.println("磁道开始位置为" + list[0]);
int num = 0;// 变量num记录寻道距离
for (int j = 0; j < list.length - 1; j++) {
num += Math.abs(list[j + 1] - list[j]);
}
System.out.println("磁盘扫描序列为:" + Arrays.toString(list));
System.out.println("寻道次数:" + num);
double w = ((float) num / (float) list.length);
System.out.println("平均寻道距离:" + w);
}
B
// 先来先服务FCSFS,即根据磁盘访问的先后次序进行调度,遍历list数组即可,所以不做赘述
private static void FCFS(int[] list) {
int i = 0;
System.out.println("请输入磁头初始位置");
Scanner sc = new Scanner(System.in);
i = sc.nextInt();
int num = 0;// 变量num记录寻道距离
num = Math.abs(i - list[0]);
for (int j = 0; j < list.length - 1; j++) {
num += Math.abs(list[j + 1] - list[j]);
}
System.out.println("磁盘扫描序列为:" + Arrays.toString(list));
System.out.println("寻道次数" + num);
double w = ((float) num / (float) list.length);
System.out.println("平均寻道距离" + w);
}
最短寻道时间优先SSTF
// 最短路径算法SSTF,即访问下一个磁道前,先计算一次当前磁头到访问各个磁道的距离
private static void SSTF(int[] list) {
int[] list1=new int[list.length];//因为下面修改了list,再次运行算法3时,list数组已经被修改,所以这里把值传给list1
System.arraycopy(list,0, list1, 0, list.length);
int i = list1[0];// 变量i记录当前磁头位置
System.out.println("磁道开始位置为" + list1[0]);
int num = 0;// num记录总寻道距离
int[] k = new int[list1.length];// k数组记录访问的每一个磁道到磁头距离
int[] templist = new int[list1.length];// 将结果保存在templist[]中
for (int a = 0; a < list1.length; a++) {
// j循环遍历出每一个访问的磁道到当前磁头的距离保存在k数组中
for (int j = 0; j < list1.length; j++) {
k[j] = Math.abs(list1[j] - i);
}
// 将k数组赋值给temp数组,对temp数组冒泡排序
int[] temp = new int[k.length];
for (int j = 0; j < k.length; j++) {
temp[j] = k[j];
}
SortA(temp);
int j = temp[0];// 找到磁头到下一个磁道距离最小的为temp[0]
// 循环遍历找到temp[0]在list磁道序列数组中的位置
for (int t = 0; t < k.length; t++) {
// if语句找到list[t]到当前磁头最近
if (k[t] == j) {
i = list1[t];// 变量i记录磁头位置
templist[a] = i;// 将结果存入templist数组中
list1[t] = 999999;// 将第g个磁道号设为999999,可以理解为权重设为99999,这样他在下一次遍历,在k数组中总是最大
break;
}
}
num += j;
}
System.out.println("磁盘扫描序列为:" + Arrays.toString(templist));
System.out.println("寻道次数:" + num);
double w = ((float) num / (float) list.length);
System.out.println("平均寻道距离:" + w);
}
B
// 最短路径算法SSTF,即访问下一个磁道前,先计算一次当前磁头到访问各个磁道的距离
private static void SSTF(int[] list) {
int i = 0;// 变量i记录当前磁头位置
int num = 0;// num记录总寻道距离
int[] templist = new int[list.length];// 将结果保存在templist[]中
int[] k = new int[list.length];// k数组记录访问的每一个磁道到磁头距离
System.out.println("请输入磁头初始位置");
Scanner sc = new Scanner(System.in);
i = sc.nextInt();
for (int a = 0; a < list.length; a++) {
// j循环遍历出每一个访问的磁道到当前磁头的距离保存在k数组中
for (int j = 0; j < list.length; j++) {
k[j] = Math.abs(list[j] - i);
}
// 将k数组赋值给temp数组,对temp数组冒泡排序
int[] temp = new int[k.length];
for (int j = 0; j < k.length; j++) {
temp[j] = k[j];
}
SortA(temp);
int j = temp[0];// 找到磁头到下一个磁道距离最小的为temp[0]
// 循环遍历找到temp[0]在list磁道序列数组中的位置
for (int t = 0; t < k.length; t++) {
// if语句找到list[t]到当前磁头最近
if (k[t] == j) {
i = list[t];// 变量i记录磁头位置
templist[a] = i;// 将结果存入templist数组中
list[t] = 999999;// 将第g个磁道号设为999999,可以理解为权重设为99999,这样他在下一次遍历,k数组中总是最大
break;
}
}
num += j;
}
System.out.println("磁盘扫描序列为:" + Arrays.toString(templist));
System.out.println("寻道次数:" + num);
double w = ((float) num / (float) list.length);
System.out.println("平均寻道距离:" + w);
}
扫描算法SCAN
写完扫描算法准备关机的时候,突然想到了另一种排序方法,B的第42行else语句中,好像可以修改修改。所以对A进行了修改。对A简单修改还可以实现CSCAN循环扫描算法,我认为A中的算法更容易理解其中的原理,所以下面着重解释!
A
/*
* 扫描算法SCAN 磁盘的0磁道在最外圈 扫描算法又叫电梯算法,即按从小到大或从大到小的顺序去依次访问磁道。
* 所以这里分两种情况,1.寻道从内向外(从大到小) 2.寻道从外向内(从小到大)
*
*
* 1.若当前磁头位置大于请求序列中最大者 2.若当前磁头位置小于请求序列中最小者 3.若当前磁道号大于请求序列中最小者且小于最大者
* 这里用同一个函数去解决三种情况
*/
private static void SCAN(int[] list) {
int[] list1=new int[list.length];//因为下面修改了list,再次运行算法3时,list数组已经被修改,所以这里把值传给list1
System.arraycopy(list,0, list1, 0, list.length);
Scanner sc = new Scanner(System.in);
int k = list1[0];// 变量i记录当前磁头位置
int tempk1 = 0;
int tempk2 = 0;
int flag=1;
int num = 0;// num记录总寻道距离
int[] templist = new int[list1.length];// 将访问顺序存入templist中
System.out.println("磁道开始位置为:" + list1[0]);
//while中先计算出磁道访问的顺序
while (true) {
System.out.println("1.磁头从外向内 2.磁头从内向外");
int choice = sc.nextInt();
if (choice == 1) {
flag=5;
SortA(list1);// 从小到大排序
// 找出重排序后,k在数组中的位置,templist记录区间[0,list.length-tempk1]
for (int i = 0; i < list1.length; i++) {
if (k == list1[i])
tempk1 = i;
}
System.arraycopy(list1, tempk1, templist, 0, list1.length - tempk1);
SortB(list1);// 从大到小
// 找出重排序后,k在数组中的位置,templist记录区间[tempk2+1,list.length]
for (int i = 0; i < list1.length; i++) {
if (k == list1[i])
tempk2 = i;
}
System.arraycopy(list1, tempk2 + 1, templist, tempk2 + 1, list1.length - tempk2 - 1);
break;
}
else if (choice == 2) {
flag=5;
SortB(list1);
// 找出重排序后,k在数组中的位置,templist记录区间[0,list.length-tempk1]
for (int i = 0; i < list1.length; i++) {
if (k == list1[i])
tempk1 = i;
}
System.arraycopy(list1, tempk1, templist, 0, list1.length - tempk1);
SortA(list1);// 从小到大
// 找出重排序后,k在数组中的位置,templist记录区间[tempk2+1,list.length]
for (int i = 0; i < list1.length; i++) {
if (k == list1[i])
tempk2 = i;
}
System.arraycopy(list1, tempk2 + 1, templist, tempk2 + 1, list1.length - tempk2 - 1);
break;
}
else if (flag==5)
break;
else
System.out.println("输入错误请重新输入");
}
//计算寻道距离
for (int j = 0; j < templist.length - 1; j++) {
num += Math.abs(templist[j + 1] - templist[j]);
}
System.out.println("磁盘扫描序列为:" + Arrays.toString(templist));
System.out.println("寻道次数" + num);
double w = ((float) num / (float) list.length);
System.out.println("平均寻道距离" + w);
}
A的解释: 可以通过以下代码及运行结果,更直白的理解最短寻道时间优先的算法。分别对list数组排序两次从而得到访问顺序
package 解释A;
import java.util.Arrays;
import java.util.Scanner;
public class paper {
// 冒泡排序(从小到大)
public static void SortA(int[] list) {
for (int i = 0; i < list.length - 1; i++) {
for (int j = 0; j < list.length - 1 - i; j++) {
if (list[j] > list[j + 1]) {
int temp = list[j];
list[j] = list[j + 1];
list[j + 1] = temp;
}
}
}
}
// 冒泡排序(从大到小)
public static void SortB(int[] list) {
for (int i = 0; i < list.length - 1; i++) {
for (int j = 0; j < list.length - 1 - i; j++) {
if (list[j] < list[j + 1]) {
int temp = list[j];
list[j] = list[j + 1];
list[j + 1] = temp;
}
}
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int[] list = { 5, 2, 3, 8, 10, 12, 9 };// 7
int[] templist = new int[list.length];
int k = list[0];
int tempk1 = 0;
int tempk2 = 0;
System.out.println("1.磁头从外向内 2.磁头从内向外(从大到小)");
int choice = sc.nextInt();
if (choice == 1) {
System.out.println("排序前的list" + Arrays.toString(list));
SortA(list);
System.out.println("从小到大的list" + Arrays.toString(list));
//找出重排序后,k在数组中的位置,templist记录区间[0,list.length-tempk1]
for (int i = 0; i < list.length; i++) {
if (k == list[i])
tempk1 = i;
}
System.arraycopy(list, tempk1, templist, 0, list.length - tempk1);
System.out.println("第一次的templist" + Arrays.toString(templist));
SortB(list);
System.out.println("从大到小的list" + Arrays.toString(list));
//找出重排序后,k在数组中的位置,templist记录区间[tempk2+1,list.length]
for (int i = 0; i < list.length; i++) {
if (k == list[i])
tempk2 = i;
}
System.arraycopy(list, tempk2 + 1, templist, tempk2 + 1, list.length - tempk2 - 1);
System.out.println("第二次的templist" + Arrays.toString(templist));
}
else if(choice==2){
System.out.println("排序前的list" + Arrays.toString(list));
SortB(list);
System.out.println("从大到小的list" + Arrays.toString(list));
//找出重排序后,k在数组中的位置,templist记录区间[0,list.length-tempk1]
for (int i = 0; i < list.length; i++) {
if (k == list[i])
tempk1 = i;
}
System.arraycopy(list, tempk1, templist, 0, list.length - tempk1);
System.out.println("第一次的templist" + Arrays.toString(templist));
SortA(list);//从小到大
System.out.println("从小到大的list" + Arrays.toString(list));
for (int i = 0; i < list.length; i++) {
if (k == list[i])
tempk2 = i;
}
System.arraycopy(list, tempk2 + 1, templist, tempk2 + 1, list.length - tempk2 - 1);
System.out.println("第二次的templist" + Arrays.toString(templist));
}
}
}
B
/*扫描算法SCAN 磁盘的0磁道在最外圈
扫描算法又叫电梯算法,即按从小到大或从大到小的顺序去依次访问磁道。
所以这里分两种情况,1.寻道从内向外(从大到小) 2.寻道从外向内(从小到大)
注意:实验要求直观的看出三种算法的区别,是以磁道序列的首磁道为磁头,用户自定义磁头方向。
这里分三种情况,按教材的案例,磁头方向从内向外
1.若当前磁头位置大于请求序列中最大者,则直接由内向外依次给予请求服务
2.若当前磁头位置小于请求序列中最小者,则直接由外向内依次给予各请求服务
3.若当前磁道号大于请求序列中最小者且小于最大者,调用SCAN算法
*/
private static void SCAN(int[] list) {
SortA(list);//先进行一次从小到大排序
int num = 0;// num记录总寻道距离
System.out.println("请输入磁头初始位置");
Scanner sc = new Scanner(System.in);
int i = sc.nextInt();//变量i记录磁头位置
int k = 0;
int[] templist=new int[list.length];//将访问顺序存入templist中
//1.若当前磁头位置大于请求序列中最大者,则直接由内向外依次给予请求服务
if(i>list[list.length-1]) {
SortB(list);//从大到小(从内向外)依次访问
System.arraycopy(list, 0, templist, 0, list.length);//将访问顺序存入templist中
//计算距离
num +=Math.abs(i- list[list.length-1]);//磁头移动到第一个磁道的距离
for (int j = 0; j < list.length - 1; j++) {
num += Math.abs(list[j + 1] - list[j]);
}
}
//2.若当前磁头位置小于请求序列中最小者,则直接由外向内依次给予各请求服务
else if(i<list[0]) {
//已经进行过从小到大排序,所以这里不用再次调用SortA
System.arraycopy(list, 0, templist, 0, list.length);
//计算距离
num +=Math.abs(i- list[list.length-1]);//磁头移动到第一个磁道的距离
for (int j = 0; j < list.length - 1; j++) {
num += Math.abs(list[j + 1] - list[j]);
}
}
//3.若当前磁头大于请求序列中最小者且小于最大者
else {
//寻找离磁头最近的访问磁道
for (int j = 0; j < list.length; j++) {
if (i <= list[j]) {
k = j;
break;
}
}
//记录磁道访问顺序到templist中
System.arraycopy(list, k, templist, 0, list.length-k);
SortB(list);
System.arraycopy(list,list.length-k, templist, list.length-k, k);
num = Math.abs(i - templist[0]);//磁头移动到第一个磁道的距离
//每个访问磁道之间的距离
for (int j = 0; j < templist.length - 1; j++) {
num += Math.abs(templist[j + 1] - templist[j]);
}
/*以下注释比较难懂,用上面这段计算距离*/
// //找到后由外向内访问(由小到大),然后再由内向外访问(从大到小)
// //两次for计算总距离
// num += list[k] - i;//磁头移动到第一个磁道的距离
// //由外向内,区间[k,list.length-1)
// for (int j = k; j < list.length - 1; j++) {
// num += list[j + 1] - list[j];
// }
// //到达最里面,再由内向外访问剩余磁道,区间[0,k-1)
// for (int j = 0; j < k - 1; j++) {
// num += Math.abs(list[j + 1] - list[j]);
// }
// num += list[list.length - 1] - list[k - 1];
}
System.out.println("磁盘扫描序列为:" + Arrays.toString(templist));
System.out.println("寻道次数" + num);
double w = ((float) num / (float) list.length);
System.out.println("平均寻道长度" + w);
}
主函数
A
public static void main(String[] args) {
// TODO Auto-generated method stub
int Tracknum;// 磁道数
System.out.println("请输入磁道数量Tracknum");
Scanner sc = new Scanner(System.in);
Tracknum = sc.nextInt();
// 随机生成磁道序列
Random r = new Random();
int[] TrackSequence = new int[Tracknum];
for (int i = 0; i < Tracknum; i++) {
TrackSequence[i] = r.nextInt(100)+1;
}
System.out.println("磁道序列为" + Arrays.toString(TrackSequence));
// 菜单
while (true) {
System.out.println("请选择算法 1.FCFS 2.SSTF 3.SCAN 0.退出");
int k = sc.nextInt();
switch (k) {
case 1:
FCFS(TrackSequence);
break;
case 2:
SSTF(TrackSequence);
break;
case 3:
SCAN(TrackSequence);
break;
case 0:
System.exit(0);
default:
System.out.println("输的不对");
}
}
}
B
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
int Tracknum;// 磁道数
// 菜单
while (true) {
System.out.println("请输入磁道数量Tracknum");
Tracknum = sc.nextInt();
// 输入磁道序列
int[] TrackSequence = new int[Tracknum];
System.out.println("磁道序列");
for (int i = 0; i < Tracknum; i++) {
TrackSequence[i] = sc.nextInt();
}
System.out.println("磁道序列为" + Arrays.toString(TrackSequence));
System.out.println("请选择算法 1.FCFS 2.SSTF 3.SCAN 0.退出");
int k = sc.nextInt();
switch (k) {
case 1:
FCFS(TrackSequence);
break;
case 2:
SSTF(TrackSequence);
break;
case 3:
SCAN(TrackSequence);
break;
case 0:
System.exit(0);
default:
System.out.println("输的不对");
}
}
}
完整代码
A
package 操作系统实验;
import java.util.Arrays;
import java.util.Random;
import java.util.Scanner;
/*
* 磁盘调度FCFS、SSTF、SCAN
* @author 张时贰
* @data 2021年12月7日
*/
public class 磁盘调度算法 {
// 冒泡排序(从小到大)
public static void SortA(int[] list) {
for (int i = 0; i < list.length - 1; i++) {
for (int j = 0; j < list.length - 1 - i; j++) {
if (list[j] > list[j + 1]) {
int temp = list[j];
list[j] = list[j + 1];
list[j + 1] = temp;
}
}
}
}
// 冒泡排序(从大到小)
public static void SortB(int[] list) {
for (int i = 0; i < list.length - 1; i++) {
for (int j = 0; j < list.length - 1 - i; j++) {
if (list[j] < list[j + 1]) {
int temp = list[j];
list[j] = list[j + 1];
list[j + 1] = temp;
}
}
}
}
// 先来先服务FCSFS,即根据磁盘访问的先后次序进行调度,遍历list数组即可,所以不做赘述
private static void FCFS(int[] list) {
System.out.println("磁道开始位置为" + list[0]);
int num = 0;// 变量num记录寻道距离
for (int j = 0; j < list.length - 1; j++) {
num += Math.abs(list[j + 1] - list[j]);
}
System.out.println("磁盘扫描序列为:" + Arrays.toString(list));
System.out.println("寻道次数:" + num);
double w = ((float) num / (float) list.length);
System.out.println("平均寻道距离:" + w);
}
// 最短路径算法SSTF,即访问下一个磁道前,先计算一次当前磁头到访问各个磁道的距离
private static void SSTF(int[] list) {
int[] list1=new int[list.length];//因为下面修改了list,再次运行算法3时,list数组已经被修改,所以这里把值传给list1
System.arraycopy(list,0, list1, 0, list.length);
int i = list1[0];// 变量i记录当前磁头位置
System.out.println("磁道开始位置为" + list1[0]);
int num = 0;// num记录总寻道距离
int[] k = new int[list1.length];// k数组记录访问的每一个磁道到磁头距离
int[] templist = new int[list1.length];// 将结果保存在templist[]中
for (int a = 0; a < list1.length; a++) {
// j循环遍历出每一个访问的磁道到当前磁头的距离保存在k数组中
for (int j = 0; j < list1.length; j++) {
k[j] = Math.abs(list1[j] - i);
}
// 将k数组赋值给temp数组,对temp数组冒泡排序
int[] temp = new int[k.length];
for (int j = 0; j < k.length; j++) {
temp[j] = k[j];
}
SortA(temp);
int j = temp[0];// 找到磁头到下一个磁道距离最小的为temp[0]
// 循环遍历找到temp[0]在list磁道序列数组中的位置
for (int t = 0; t < k.length; t++) {
// if语句找到list[t]到当前磁头最近
if (k[t] == j) {
i = list1[t];// 变量i记录磁头位置
templist[a] = i;// 将结果存入templist数组中
list1[t] = 999999;// 将第g个磁道号设为999999,可以理解为权重设为99999,这样他在下一次遍历,在k数组中总是最大
break;
}
}
num += j;
}
System.out.println("磁盘扫描序列为:" + Arrays.toString(templist));
System.out.println("寻道次数:" + num);
double w = ((float) num / (float) list.length);
System.out.println("平均寻道距离:" + w);
}
/*
* 扫描算法SCAN 磁盘的0磁道在最外圈 扫描算法又叫电梯算法,即按从小到大或从大到小的顺序去依次访问磁道。
* 所以这里分两种情况,1.寻道从内向外(从大到小) 2.寻道从外向内(从小到大)
*
*
* 1.若当前磁头位置大于请求序列中最大者 2.若当前磁头位置小于请求序列中最小者 3.若当前磁道号大于请求序列中最小者且小于最大者
* 这里用同一个函数去解决三种情况
*/
private static void SCAN(int[] list) {
int[] list1=new int[list.length];//因为下面修改了list,再次运行算法3时,list数组已经被修改,所以这里把值传给list1
System.arraycopy(list,0, list1, 0, list.length);
Scanner sc = new Scanner(System.in);
int k = list1[0];// 变量i记录当前磁头位置
int tempk1 = 0;
int tempk2 = 0;
int flag=1;
int num = 0;// num记录总寻道距离
int[] templist = new int[list1.length];// 将访问顺序存入templist中
System.out.println("磁道开始位置为:" + list1[0]);
//while中先计算出磁道访问的顺序
while (true) {
System.out.println("1.磁头从外向内 2.磁头从内向外");
int choice = sc.nextInt();
if (choice == 1) {
flag=5;
SortA(list1);// 从小到大排序
// 找出重排序后,k在数组中的位置,templist记录区间[0,list.length-tempk1]
for (int i = 0; i < list1.length; i++) {
if (k == list1[i])
tempk1 = i;
}
System.arraycopy(list1, tempk1, templist, 0, list1.length - tempk1);
SortB(list1);// 从大到小
// 找出重排序后,k在数组中的位置,templist记录区间[tempk2+1,list.length]
for (int i = 0; i < list1.length; i++) {
if (k == list1[i])
tempk2 = i;
}
System.arraycopy(list1, tempk2 + 1, templist, tempk2 + 1, list1.length - tempk2 - 1);
break;
}
else if (choice == 2) {
flag=5;
SortB(list1);
// 找出重排序后,k在数组中的位置,templist记录区间[0,list.length-tempk1]
for (int i = 0; i < list1.length; i++) {
if (k == list1[i])
tempk1 = i;
}
System.arraycopy(list1, tempk1, templist, 0, list1.length - tempk1);
SortA(list1);// 从小到大
// 找出重排序后,k在数组中的位置,templist记录区间[tempk2+1,list.length]
for (int i = 0; i < list1.length; i++) {
if (k == list1[i])
tempk2 = i;
}
System.arraycopy(list1, tempk2 + 1, templist, tempk2 + 1, list1.length - tempk2 - 1);
break;
}
else if (flag==5)
break;
else
System.out.println("输入错误请重新输入");
}
//计算寻道距离
for (int j = 0; j < templist.length - 1; j++) {
num += Math.abs(templist[j + 1] - templist[j]);
}
System.out.println("磁盘扫描序列为:" + Arrays.toString(templist));
System.out.println("寻道次数" + num);
double w = ((float) num / (float) list.length);
System.out.println("平均寻道距离" + w);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int Tracknum;// 磁道数
System.out.println("请输入磁道数量Tracknum");
Scanner sc = new Scanner(System.in);
Tracknum = sc.nextInt();
// 随机生成磁道序列
Random r = new Random();
int[] TrackSequence = new int[Tracknum];
for (int i = 0; i < Tracknum; i++) {
TrackSequence[i] = r.nextInt(100)+1;
}
System.out.println("磁道序列为" + Arrays.toString(TrackSequence));
// 菜单
while (true) {
System.out.println("请选择算法 1.FCFS 2.SSTF 3.SCAN 0.退出");
int k = sc.nextInt();
switch (k) {
case 1:
FCFS(TrackSequence);
break;
case 2:
SSTF(TrackSequence);
break;
case 3:
SCAN(TrackSequence);
break;
case 0:
System.exit(0);
default:
System.out.println("输的不对");
}
}
}
}
B
package 操作系统实验;
import java.util.Arrays;
import java.util.Random;
import java.util.Scanner;
/*
* 磁盘调度FCFS、SSTF、SCAN
* @author 张时贰
* @data 2021年12月7日
*/
public class 磁盘调度算法自定义磁头 {
// 冒泡排序(从小到大)
public static void SortA(int[] list) {
for (int i = 0; i < list.length - 1; i++) {
for (int j = 0; j < list.length - 1 - i; j++) {
if (list[j] > list[j + 1]) {
int temp = list[j];
list[j] = list[j + 1];
list[j + 1] = temp;
}
}
}
}
// 冒泡排序(从大到小)
public static void SortB(int[] list) {
for (int i = 0; i < list.length - 1; i++) {
for (int j = 0; j < list.length - 1 - i; j++) {
if (list[j] < list[j + 1]) {
int temp = list[j];
list[j] = list[j + 1];
list[j + 1] = temp;
}
}
}
}
// 先来先服务FCSFS,即根据磁盘访问的先后次序进行调度,遍历list数组即可,所以不做赘述
private static void FCFS(int[] list) {
int i = 0;
System.out.println("请输入磁头初始位置");
Scanner sc = new Scanner(System.in);
i = sc.nextInt();
int num = 0;// 变量num记录寻道距离
num = Math.abs(i - list[0]);
for (int j = 0; j < list.length - 1; j++) {
num += Math.abs(list[j + 1] - list[j]);
}
System.out.println("磁盘扫描序列为:" + Arrays.toString(list));
System.out.println("寻道次数" + num);
double w = ((float) num / (float) list.length);
System.out.println("平均寻道距离" + w);
}
// 最短路径算法SSTF,即访问下一个磁道前,先计算一次当前磁头到访问各个磁道的距离
private static void SSTF(int[] list) {
int i = 0;// 变量i记录当前磁头位置
int num = 0;// num记录总寻道距离
int[] templist = new int[list.length];// 将结果保存在templist[]中
int[] k = new int[list.length];// k数组记录访问的每一个磁道到磁头距离
System.out.println("请输入磁头初始位置");
Scanner sc = new Scanner(System.in);
i = sc.nextInt();
for (int a = 0; a < list.length; a++) {
// j循环遍历出每一个访问的磁道到当前磁头的距离保存在k数组中
for (int j = 0; j < list.length; j++) {
k[j] = Math.abs(list[j] - i);
}
// 将k数组赋值给temp数组,对temp数组冒泡排序
int[] temp = new int[k.length];
for (int j = 0; j < k.length; j++) {
temp[j] = k[j];
}
SortA(temp);
int j = temp[0];// 找到磁头到下一个磁道距离最小的为temp[0]
// 循环遍历找到temp[0]在list磁道序列数组中的位置
for (int t = 0; t < k.length; t++) {
// if语句找到list[t]到当前磁头最近
if (k[t] == j) {
i = list[t];// 变量i记录磁头位置
templist[a] = i;// 将结果存入templist数组中
list[t] = 999999;// 将第g个磁道号设为999999,可以理解为权重设为99999,这样他在下一次遍历,k数组中总是最大
break;
}
}
num += j;
}
System.out.println("磁盘扫描序列为:" + Arrays.toString(templist));
System.out.println("寻道次数:" + num);
double w = ((float) num / (float) list.length);
System.out.println("平均寻道距离:" + w);
}
/*扫描算法SCAN 磁盘的0磁道在最外圈
扫描算法又叫电梯算法,即按从小到大或从大到小的顺序去依次访问磁道。
所以这里分两种情况,1.寻道从内向外(从大到小) 2.寻道从外向内(从小到大)
注意:实验要求直观的看出三种算法的区别,是以磁道序列的首磁道为磁头,用户自定义磁头方向。
这里分三种情况,按教材的案例,磁头方向从内向外
1.若当前磁头位置大于请求序列中最大者,则直接由内向外依次给予请求服务
2.若当前磁头位置小于请求序列中最小者,则直接由外向内依次给予各请求服务
3.若当前磁道号大于请求序列中最小者且小于最大者,调用SCAN算法
*/
private static void SCAN(int[] list) {
SortA(list);//先进行一次从小到大排序
int num = 0;// num记录总寻道距离
System.out.println("请输入磁头初始位置");
Scanner sc = new Scanner(System.in);
int i = sc.nextInt();//变量i记录磁头位置
int k = 0;
int[] templist=new int[list.length];//将访问顺序存入templist中
//1.若当前磁头位置大于请求序列中最大者,则直接由内向外依次给予请求服务
if(i>list[list.length-1]) {
SortB(list);//从大到小(从内向外)依次访问
System.arraycopy(list, 0, templist, 0, list.length);//将访问顺序存入templist中
//计算距离
num +=Math.abs(i- list[list.length-1]);//磁头移动到第一个磁道的距离
for (int j = 0; j < list.length - 1; j++) {
num += Math.abs(list[j + 1] - list[j]);
}
}
//2.若当前磁头位置小于请求序列中最小者,则直接由外向内依次给予各请求服务
else if(i<list[0]) {
//已经进行过从小到大排序,所以这里不用再次调用SortA
System.arraycopy(list, 0, templist, 0, list.length);
//计算距离
num +=Math.abs(i- list[list.length-1]);//磁头移动到第一个磁道的距离
for (int j = 0; j < list.length - 1; j++) {
num += Math.abs(list[j + 1] - list[j]);
}
}
//3.若当前磁头大于请求序列中最小者且小于最大者
else {
//寻找离磁头最近的访问磁道
for (int j = 0; j < list.length; j++) {
if (i <= list[j]) {
k = j;
break;
}
}
//记录磁道访问顺序到templist中
System.arraycopy(list, k, templist, 0, list.length-k);
SortB(list);
System.arraycopy(list,list.length-k, templist, list.length-k, k);
num = Math.abs(i - templist[0]);//磁头移动到第一个磁道的距离
//每个访问磁道之间的距离
for (int j = 0; j < templist.length - 1; j++) {
num += Math.abs(templist[j + 1] - templist[j]);
}
/*以下注释比较难懂,用上面这段计算距离*/
// //找到后由外向内访问(由小到大),然后再由内向外访问(从大到小)
// //两次for计算总距离
// num += list[k] - i;//磁头移动到第一个磁道的距离
// //由外向内,区间[k,list.length-1)
// for (int j = k; j < list.length - 1; j++) {
// num += list[j + 1] - list[j];
// }
// //到达最里面,再由内向外访问剩余磁道,区间[0,k-1)
// for (int j = 0; j < k - 1; j++) {
// num += Math.abs(list[j + 1] - list[j]);
// }
// num += list[list.length - 1] - list[k - 1];
}
System.out.println("磁盘扫描序列为:" + Arrays.toString(templist));
System.out.println("寻道次数" + num);
double w = ((float) num / (float) list.length);
System.out.println("平均寻道长度" + w);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
int Tracknum;// 磁道数
// 菜单
while (true) {
System.out.println("请输入磁道数量Tracknum");
Tracknum = sc.nextInt();
// 输入磁道序列
int[] TrackSequence = new int[Tracknum];
System.out.println("磁道序列");
for (int i = 0; i < Tracknum; i++) {
TrackSequence[i] = sc.nextInt();
}
System.out.println("磁道序列为" + Arrays.toString(TrackSequence));
System.out.println("请选择算法 1.FCFS 2.SSTF 3.SCAN 0.退出");
int k = sc.nextInt();
switch (k) {
case 1:
FCFS(TrackSequence);
break;
case 2:
SSTF(TrackSequence);
break;
case 3:
SCAN(TrackSequence);
break;
case 0:
System.exit(0);
default:
System.out.println("输的不对");
}
}
}
}
运行结果
这里使用课本P233页的磁道序列:55 58 39 18 90 160 150 38 184,磁头初始位置都为100。因为A的磁道序列是随机生成的,这里运行结果使用B代码,方便对比 先来先服务FCFS
| 被访问的下一个磁道号 | 移动距离(磁道数) |
|---|---|
| 55 | 45 |
| 58 | 3 |
| 39 | 19 |
| 18 | 21 |
| 90 | 72 |
| 160 | 70 |
| 150 | 10 |
| 38 | 112 |
| 184 | 146 |
| 平均寻道长度 | 55.3 |
最短寻道时间优先SSTF
| 被访问的下一个磁道号 | 移动距离(磁道数) |
|---|---|
| 90 | 10 |
| 58 | 32 |
| 55 | 3 |
| 39 | 16 |
| 38 | 1 |
| 18 | 20 |
| 150 | 132 |
| 160 | 10 |
| 184 | 24 |
| 平均寻道长度 | 27.5 |
扫描算法SCAN
| 被访问的下一个磁道号 | 移动距离(磁道数) |
|---|---|
| 150 | 50 |
| 160 | 10 |
| 184 | 24 |
| 90 | 94 |
| 58 | 32 |
| 55 | 3 |
| 39 | 16 |
| 38 | 1 |
| 18 | 20 |
| 平均寻道长度 | 27.8 |
A的运行结果
学习到的新东西!
1.这段代码看着好像没什么问题,菜单也一直这样写,但是他是一个死循环(菜单也是死循环但是菜单之后不执行其它代码所以不影响)
while (true) {
System.out.println("1.从内向外依次访问 2.从外向内依次访问");
Scanner sc = new Scanner(System.in);
int choice = sc.nextInt();
switch (choice) {
case 1:
Sort(list);// 对list从小到大冒泡排序,即从内向外依次访问
break;
case 2:
SortB(list);// 对list从大到小冒泡排序,即从外向内依次访问
break;
default:
System.out.println("输的不对,重新输入");
}
}
int flag=0;
while (true) {
System.out.println("1.从内向外依次访问 2.从外向内依次访问");
Scanner sc = new Scanner(System.in);
int choice = sc.nextInt();
switch (choice) {
case 1:
Sort(list);// 对list从小到大冒泡排序,即从内向外依次访问
flag++;
break;
case 2:
SortB(list);// 对list从大到小冒泡排序,即从外向内依次访问
flag++;
break;
default:
System.out.println("输的不对,重新输入");
}
if(flag!=0)
break;
}
2.对数组遍历
System.out.println(Arrays.toString(templist));
3.对数组的值传递
System.arraycopy(list, 0, templist, 0, list.length);//(数组名,数组位置,数组名,数组位置,传递个数)
总结
磁盘访问时间主要有哪些部分构成?要提高磁盘调度效率,主要在哪方面下手更好?
磁盘访问时间主要由寻道时间,旋转延迟时间,传输时间构成。集中数据传输,有利于提高传输效率
最短寻道时间优先算法与扫描(电梯)算法有什么异同?如何改进SCAN算法?
最短寻道时间优先算法是基于优先级的调度算法,因此就可能导致优先级低的进程发生饥饿现象,而扫描算法不仅考虑距离,更优先考虑磁头的移动方向。改进SCAN算法,规定磁头单向移动,即从内向外访问,到达最外面,磁头立即返回内侧