实验(四)磁盘调度算法模拟

一、实验名称

实验(四)磁盘调度算法模拟

二、实验目的

掌握磁盘调度的策略及原理,理解和掌握磁盘调度算法——先来先服务算法(FCFS)、最短寻道时间优先算法(SSTF)、电梯扫描算法(SCAN),比较各算法相关特性。

三、实验内容和要求

(1)模拟先来先服务法(FCFS),最短寻道时间优先法(SSTF),电梯扫描算法(SCAN)三种磁盘调度算法;
(2)输入两组请求访问磁道序列,分别输出每种调度算法的磁头移动轨迹和移动的总磁道数。

四、实验设计

1、程序流程图:

在这里插入图片描述

2、实验环境:jdk1.8

3、代码与注释

package com.symc.dsaa.os.test4;

import java.util.Scanner;

/**
 * @Author: 凤文  沈阳医学院2019级医学信息工程 0213
 * @CreateTime: 2021/12/05 17:28
 * @Description: 磁盘调度算法实验
 */
public class Test {
    public static void main(String[] args) {
        int[] tracks = getRandomArr();
        System.out.println("随机生成了10个磁道号(0-200)");
        for (int track : tracks) {
            System.out.print(track + "\t");
        }
        System.out.println();
        Scanner sc = new Scanner(System.in);
        System.out.println("请设置一个起始的磁道号(0-200):");
        int startTrack;
        while (true) {
            startTrack = sc.nextInt();
            if (startTrack < 0 || startTrack > 200) {
                System.out.println("您输入的磁道号越界,请重新设置(0-200):");
                continue;
            }
            break;
        }
        do {
            printMenu();
        } while (choose(sc, tracks, startTrack));

    }

    public static void printMenu() {
        System.out.println("##########################");
        System.out.println("请选择您想用的算法:");
        System.out.println("1.先来先服务");
        System.out.println("2.最短寻道时间优先");
        System.out.println("3.扫描算法");
        System.out.println("0.退出本次实验");
        System.out.println("##########################");

    }

    /**
     * 随机生成一个0-200的序列来代替磁道号
     * 用随机的目的是方便快速测试
     * @return
     */
    public static int[] getRandomArr() {
        int[] arr = new int[10];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = (int) (Math.random() * 200);
        }
        return arr;
    }

    public static boolean choose(Scanner sc, int[] tracks, int startTrack) {
        int option = sc.nextInt();
        switch (option) {
            case 0:
                return false;
            case 1:
                printFCFS(tracks, startTrack);
                break;
            case 2:
                printSSTF(tracks, startTrack);
                break;
            case 3:
                printSCAN(tracks, startTrack, 1);
                break;
            default:
                System.out.println("输入错误!请重新输入!");
                choose(sc, tracks, startTrack);
                break;
        }
        return true;
    }

    public static void printFCFS(int[] tracks, int startTrack) {
        int[] sequence = DiskScheduling.FCFS(tracks);
        int[] move = DiskScheduling.move(sequence, startTrack);
        print(sequence, move, startTrack);
    }

    public static void printSSTF(int[] tracks, int startTrack) {
        int[] sequence = DiskScheduling.SSTF(tracks, startTrack);
        int[] move = DiskScheduling.move(sequence, startTrack);
        print(sequence, move, startTrack);
    }

    public static void printSCAN(int[] tracks, int startTrack, int direction) {
        int[] sequence = DiskScheduling.SSTF(tracks, startTrack);
        int[] move = DiskScheduling.move(sequence, startTrack);
        if (direction > 0) {
            System.out.println("向磁道号增加方向访问");
            print(sequence, move, direction);
        } else {
            System.out.println("向磁道号减少方向访问");
        }
    }

    public static void print(int[] sequence, int[] move, int startTrack) {
        System.out.println("从" + startTrack + "号磁道开始");
        System.out.println("被访问的下一个磁道号\t移动距离(磁道数)");
        int averMove = 0;
        for (int i = 0; i < sequence.length; i++) {
            System.out.println(sequence[i] + "\t\t\t\t\t" + move[i]);
            averMove += move[i];
        }
        System.out.println("平均寻道长度:" + (double) averMove / sequence.length);
    }
}

package com.symc.dsaa.os.test4;

import java.util.Arrays;
import java.util.Stack;
/**
 * @Author: 凤文  沈阳医学院2019级医学信息工程 0213
 * @CreateTime: 2021/12/05 17:28
 * @Description:
 */
public class DiskScheduling {

    /**
     * 先来先服务
     * @param tracks 传入一组乱序的磁盘轨道序列
     * @return 返回一组FCFS的磁头移动轨迹的序列
     */
    public static int[] FCFS(int[] tracks) {
        int len = tracks.length;
        int[] sequence = new int[len];
        for (int i = 0; i < len; i++) {
            sequence[i] = tracks[i];
        }
        return sequence;
    }

    /**
     * 最短寻道时间优先
     * @param tracks 传入一组乱序的磁盘轨道序列
     * @param startTrack 需要知道磁头的起始位置
     * @return 返回一组SSTF的磁头移动轨迹的序列
     */
    public static int[] SSTF(int[] tracks, int startTrack) {
        Stack<Integer> stack1 = new Stack<Integer>();
        Stack<Integer> stack2 = new Stack<Integer>();
        Stack<Integer> stack2Temp = new Stack<Integer>();
        Arrays.stream(tracks).sorted().forEach((track) -> {
            if (track <= startTrack) {
                stack1.push(track);
            } else if (track > startTrack) {
                stack2Temp.push(track);
            }
        });
        while (!stack2Temp.isEmpty()) {
            stack2.push(stack2Temp.pop());
        }
        int head = startTrack;
        int[] sequence = new int[tracks.length];
        for (int i = 0; i < sequence.length; i++) {
            if (stack1.isEmpty()) {
                head = stack2.pop();
                sequence[i] = head;
                continue;
            }
            if (stack2.isEmpty()) {
                head = stack1.pop();
                sequence[i] = head;
                continue;
            }

            if (stack2.peek() - head < head - stack1.peek()) {
                head = stack2.pop();
                sequence[i] = head;
            } else {
                head = stack1.pop();
                sequence[i] = head;
            }
        }
        return sequence;
    }

    /**
     * 电梯扫描
     * @param tracks 传入一组乱序的磁盘轨道序列
     * @param startTrack 需要知道磁头的起始位置
     * @param direction 扫描算法还需要知道磁头起始的移动方向
     * @return 返回一组SCAN的磁头移动轨迹的序列
     */
    public static int[] SCAN(int[] tracks, int startTrack, int direction) {
        int len = tracks.length;
        int[] sequence = new int[len];
        for (int i = 0; i < len; i++) {
            sequence[i] = tracks[i];
        }
        Arrays.sort(sequence);
        int num =
                (int) Arrays.stream(sequence).filter(track -> track < startTrack).count();
        int[] reSequence = new int[num];
        for (int i = 0; i < sequence.length; i++) {
            if (sequence[i]<startTrack){
                reSequence[i]=sequence[i];
            }else {
                sequence[i-num]=sequence[i];
            }
        }
        for (int i = num-1; i >= 0; i--) {
            sequence[len-i-1] = reSequence[i];
        }

        return sequence;
    }

/**
 * 移动序列确定好之后,移动距离的算法都一致,都使用move即可
 * @param sequence
 * @param startTrack
 * @return 返回一个存放移动距离的数组
 */
    public static int[] move(int[] sequence, int startTrack) {
        int len = sequence.length;
        int[] trackValues = new int[len];
        int trackNum;
        for (int i = 0; i < len; i++) {
            if (i == 0) {
                trackNum = startTrack - sequence[i];
            } else {
                trackNum = sequence[i] - sequence[i - 1];
            }
            trackValues[i] = trackNum > 0 ? trackNum : -trackNum;
        }
        return trackValues;
    }
}

五、实验步骤及实验结果

1、实验内容

在这里插入图片描述

2、实验结果

选择先来先服务结果如下:

在这里插入图片描述

最短寻道时间优先:
在这里插入图片描述
扫描算法:
在这里插入图片描述
结束本次实验:
在这里插入图片描述
为了避免偶然性,我们可以进行多次实验,每次运行后都将这个序列按照这三种算法测试。

六、实验中出现的问题及解决方法

问题1:SSTF算法的实现

这个算法需要我们比较当前磁头的位置与哪个序列最近,在实现的时候,无论是使用数组还是ArrayList,发现它实现思路特别麻烦。于是,我想了新的思路,使用双栈。首先,肯定要把磁道序列先排序,就按从小到大升序,然后把比磁头位置大的磁道号全放到一个栈,栈内顺序就是大的放最下面,比磁头位置小的磁道号全放到另一个栈,栈内顺序就是小的放最下面,假如有一个排序好的序列:5,10,12,17,20,40,60,磁头位置在15,结构如图:

我们只需要比较磁头与两个栈顶的磁道哪个差值最小,那这个栈顶就是下一个访问的磁道,比如这里,12跟15相差3,17跟15相差2,那下一个序列就是17。同时要注意这个栈顶17要取出,然后磁头位置由15变成了17,下一轮继续这么比较。代码实现如下:

public static int[] SSTF(int[] tracks, int startTrack) {

Stack<Integer> stack1 = new Stack<Integer>();

Stack<Integer> stack2 = new Stack<Integer>();

Stack<Integer> stack2Temp = new Stack<Integer>();

Arrays.stream(tracks).sorted().forEach((track) -> { //我这里使用了stream去排序

    if (track <= startTrack) { //排好序后放到对应的栈内
        stack1.push(track);
    } else if (track > startTrack) {
        stack2Temp.push(track);
    }
});

while (!stack2Temp.isEmpty()) { 
    stack2.push(stack2Temp.pop());
}

int head = startTrack;
int[] sequence = new int[tracks.length];
for (int i = 0; i < sequence.length; i++) {
    if (stack1.isEmpty()) {//当比较前,如果发现有一个栈是空的,那就不用比较了
        head = stack2.pop();//说明只能访问另一个栈,磁头也要指向对应的位置
        sequence[i] = head;
        continue;
    }
    
    if (stack2.isEmpty()) {
        head = stack1.pop();
        sequence[i] = head;
        continue;
    }

    if (stack2.peek() - head < head - stack1.peek()) { //比较出下一个访问的磁道
        head = stack2.pop();
        sequence[i] = head;
    } else {
        head = stack1.pop();
        sequence[i] = head;
    }
}
return sequence;

}

七、结论

FIFS:其平均寻道时间较大,故只适合请求磁盘I/O进程数目较少的场合
SSTF:保证每次的寻道时间最短,但不能保证平均寻道时间最短
可防止低优先级进程出现饥饿现象

  • 4
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值