操作系统实验报告-移动臂调度算法的模拟实现
一、实验目的和要求
掌握操作系统的设备管理功能,熟悉移动臂调度算法,设计恰当的数据结构和算法,模拟实现移动臂调度算法。
熟练掌握一种以上的开发工具,如C++、JAVA、Delphi、VB等,掌握基本的编程技巧,自由选择一种编程语言设计并实现实验内容。
二、实验方法与步骤(需求分析、算法设计思路、流程图等)
需求分析:磁盘移臂调度的目标就是要使磁盘访问的总时间中的寻找时间最小。因此,磁盘移臂调度要尽量减少磁盘移动臂移动的距离。磁盘移臂调度算法很多,本实验通过模拟先来先服务调度算法(FCFS),最短寻找时间优先调度算法(SSTF),电梯调度算法(Elevator)。通过对比各算法中移动臂的移动距离,平均寻道长度等指标评判各算法的优缺点。
算法设计思路:
①先来先服务调度算法(FCFS):先来先服务算法只根据请求者的时间先后顺序,先请求的先得到服务。
②最短寻找时间优先调度算法(SSTF):最短寻找时间调度算法总是使寻找时间最短的请求最先得到服务,跟请求者的时间先后顺序无关。
③电梯调度算法(Elevator):移动臂朝一个方向进行运动,将该方向上的所有请求依次进行服务,当该方向上没有请求时,移动臂就改变方向,然后将改变的方向上的请求依次进行服务,直到该方向上没有请求,然后再改变移动方向。
三、实验原始纪录(源程序、数据结构等)
1.数据结构(磁盘对象):
public class CiPan {
Integer[] zhumian; //请求柱面号数组
}
2.算法实现代码
①先来先服务调度算法:
public void fifo(int x) {
Integer length = 0; //移动臂移动距离
//按照请求柱面号的先后顺序依次访问
System.out.println("当前磁头位于柱面"+x+",采用先来先服务调度算法,服务序列如下:");
//x为正在服务的柱面
System.out.print(x+" ");
for (Integer integer : this.zhumian) {
int size = Math.abs(x-integer);
length += size;
x = integer;
System.out.print(integer+ " ");
}
System.out.println();
System.out.println("移动距离:"+length);
double avg = (double)length/(double)this.zhumian.length;
System.out.println("平均寻道长度:" + avg);
}
②最短寻找时间优先调度算法:
public void sstf(int x) {
Integer length = 0;
System.out.println("当前磁头位于柱面"+x+",采用最短寻找时间优先调度算法,服务序列如下:");
//结果集合,x为正在服务的柱面
List<Integer> res = new ArrayList<>();
res.add(x);
//请求柱面放入数组集合中,方便操作
List<Integer> list = new ArrayList<Integer>();
Collections.addAll(list,this.zhumian);
//找出集合中距离当前正在服务柱面最近的柱面,将该柱面添加到结果集合,并从原集合中删除
while (list.size()>0) {
int index = findMin(res.get(res.size()-1),list);
res.add(list.get(index));
list.remove(index);
}
//输出集合,计算距离之和
for (Integer n : res) {
int size = Math.abs(n-x);
length += size;
x = n;
System.out.print(n + " ");
}
System.out.println();
System.out.println("移动距离:"+length);
double avg = (double)length/(double)this.zhumian.length;
System.out.println("平均寻道长度:" + avg);
}
//找到集合list中距离柱面last最近的索引
public int findMin(int last, List<Integer> list) {
int min = Math.abs(last-list.get(0));
int index = 0;
for (int i = 0; i <list.size(); i++) {
if (Math.abs(list.get(i)-last) < min) {
min = Math.abs(list.get(i)-last);
index = i;
}
}
return index;
}
③电梯调度算法
public void elevator(int x, int y) {
Integer length = 0;
System.out.println("当前磁头位于柱面"+x+",采用电梯调度算法,服务序列如下:");
Arrays.sort(this.zhumian);
//y为已完成请求的柱面,x为正在服务的柱面。x>y证明移动臂正向扫描,反之负向扫描
List<Integer> res = new ArrayList<>();
res.add(x);
if (x > y) {
forward(this.zhumian, x, res);
negative(this.zhumian, x, res);
}else {
negative(this.zhumian, x, res);
forward(this.zhumian, x, res);
}
//输出集合,计算距离之和
for (Integer n : res) {
int size = Math.abs(n-x);
length += size;
x = n;
System.out.print(n+ " ");
}
System.out.println();
System.out.println("移动距离:"+length);
double avg = (double)length/(double)this.zhumian.length;
System.out.println("平均寻道长度:" + avg);
}
//正向访问柱面
public void forward(Integer[] arrs, int x, List<Integer> res) {
for (Integer arr : arrs) {
if (arr>=x) {
res.add(arr);
}
}
}
//负向访问柱面
public void negative(Integer[] arrs, int x, List<Integer> res) {
for (int i = arrs.length-1; i >= 0; i--) {
if (arrs[i] <= x) {
res.add(arrs[i]);
}
}
}
3.测试代码:
public class Test {
public static void main(String[] args) {
Integer[] list = {10, 22, 21, 2, 40, 6, 38, 67, 99, 50};
CiPan c = new CiPan(list);
c.fifo(20); //当前正在服务柱面20
System.out.println("-----------------------------");
c.sstf(20); //当前正在服务柱面20
System.out.println("-----------------------------");
c.elevator(20,15); //已完成柱面15请求,当前正在前服务柱面20
}
}
四、实验结果及分析(计算过程与结果、数据曲线、图表等)
过程分析:
先来先服务调度算法实现简单,表面上最公平,每个请求都会得到服务,不会出现“饿死”现象;最短寻找时间调度算法具有比先来先服务更好的性能,但是发现若靠近磁头的请求不断到来,则离磁头较远的请求会出现“饿死”;电梯调度算法可以看作是最短寻找时间优先的改进,不会“饿死”。
结果分析:
从运行结果来看,先来先服务调度算法平均寻找时间很长,可能频繁改变移动臂方向,磁盘效率很低;最短寻找时间优先算法可以获得到较短的平均响应时间,有较好的吞吐量,但和先来先服务一样可能频繁改变移动臂方向;电梯调度算法克服了频繁改变移动臂方向,效率也要由于先来先服务。
五、实验改进与思考
通过此次实验,加深了我对操作系统设备管理的认识,清楚的了解到磁盘调度的详细过程和五种调度算法(先来先服务算法;最短寻道时间优先算法;单向扫描算法;双向扫描算法;电梯调度算法)以及五种调度算法之间的差异和共性,同时,也看到了经过优化的算法会带来的好处!
这次实验由于扫描算法和电梯调度算法的基本思路较为相似,因此我省略了扫描算法的实现。理清了每种算法的流程和特点,实现起来也并不是很困难。在实验过程中,也遇到了不少问题,如在电梯调度算法中,没有考虑到判断移动方向的问题,单纯从一个方向移动,通过老师的指点,我添加了移动方向的判断条件,经过调整后,程序更加完整。在最短时间优先算法中,实现找当前服务柱面最近柱面时,思路很乱导致代码冗杂,最后通过画流程图理清思路后,优化了代码,让代码更加简洁易懂。感觉这个方法极其重要,实现代码时先将流程图画出来,代码编写就容易得多。