实验五 磁盘管理实验
- 实验目的-
- 了解磁盘调度的策略和原理;
- 理解和掌握磁盘调度算法——先来先服务算法(FCFS)、最短寻道时间优先算法(SSTF)、电梯扫描算法(SCAN)。
- 实验内容
- 模拟先来先服务法(First-Come, First-Served,FCFS),最短寻道时间优先法(Shortest Seek Time First, SSTF),电梯扫描算法(SCAN)三种磁盘调度算法;
- 对三种算法进行对比分析。
- 输入为一组请求访问磁道序列,输出为每种调度算法的磁头移动轨迹和移动的总磁道数。
- 实验原理
1、先来先服务算法(FCFS): 按先来后到次序服务,未作优化。最简单的移臂调度算法是“先来先服务”调度算法,这个算法实际上不考虑访问者要求访问的物理位置,而只是考虑访问者提出访问请求的先后次序。 采用先来先服务算法决定等待访问者执行输入输出操作的次序时,移动臂来回地移动。先来先服务算法花费的寻找时间较长,所以执行输入输出操作的总时间也很长。
2、最短寻道时间优先算法(SSTF) : 最短寻找时间优先调度算法总是从等待访问者中挑选寻找时间最短的那个请求先执行的,而不管访问者到来的先后次序。与先来先服务、算法比较,大幅度地减少了寻找时间,因而缩短了为各访问者请求服务的平均时间,也就提高了系统效率。但最短查找时间优先(SSTF)调度,FCFS会引起读写头在盘面上的大范围移动,SSTF查找距离磁头最短(也就是查找时间最短)的请求作为下一次服务的对象。SSTF查找模式有高度局部化的倾向,会推迟一些请求的服务,甚至引起无限拖延(又称饥饿)。
3、扫描算法(SCAN): SCAN 算法又称电梯调度算法。SCAN算法是磁头前进方向上的最短查找时间优先算法,它排除了磁头在盘面局部位置上的往复移动,SCAN算法在很大程度上消除了SSTF算法的不公平性,但仍有利于对中间磁道的请求。“电梯调度”算法是从移动臂当前位置开始沿着臂的移动方向去选择离当前移动臂最近的那个柱访问者,如果沿臂的移动方向无请求访问时,就改变臂的移动方向再选择。但是,“电梯调度”算法在实现时,不仅要记住读写磁头的当前位置,还必须记住移动臂的当前前进方向。
- 实验中用到的系统调用函数
实验只是模拟实现磁盘调度功能,不需要系统调用函数。
- 实验步骤
- 输入为一组请求访问磁道序列,该序列和所选磁道个数要求随机生成,输出为每种调度算法的磁头移动轨迹和移动的总磁道数;
随机生成磁道个数和序列
磁道轨迹:
移动的总磁道数:
- 输入磁道范围 0~1000 ,输入所选磁道个数0~1000;
代码:
srand((unsigned)time(NULL));
N = rand() % MAX;//在0-1000中随机生成磁道总数
start = rand() & MAX;//在0-N中随机生成初始磁头位置
queue = new int[N];
for (int i = 0; i < N; i++) { //初始化队列
queue[i] = rand() %MAX;
}
多次测试的截图
3、画出主程序流程图;
总流程图:
先来先服务算法
最短寻道时间优先算法
电梯扫描算法
4、 编写程序并调试;
#include<time.h>
#include<iostream>
using namespace std;
#define MAX 1001 //磁道总数范围为0-1000
int N;//磁道总数
int start;//磁头初始位置
int* queue;//请求磁盘服务队列
void init() {
srand((unsigned)time(NULL));
N = rand() % MAX;//在0-1000中随机生成磁道总数
start = rand() & MAX;//在0-N中随机生成初始磁头位置
queue = new int[N];
for (int i = 0; i < N; i++) { //初始化队列
queue[i] = rand() %MAX;
}
cout << "**********************************" << endl;
cout<<"****初始化随机生成磁道总数为:"<<N<<"***"<<endl;
cout << "****随机生成的初始磁头位置为:" << start <<"***"<< endl;
cout << "**********************************" << endl;
cout << endl;
cout<<"*****************磁道序列*****************"<<endl;
for (int i = 0; i < N; i++)
cout<<"->"<<queue[i]; //输出队列
cout << endl;
}
void release() {//进程完成,释放资源
free(queue);
}
void FCFS() {//先来先服务算法
int steps = 0, move = start;
cout<<"磁头移动轨迹为:"<<start;
for (int i = 0; i < N; i++) {
cout<<"->" << queue[i];
steps += abs(queue[i] - move); //记录移动的磁道数
move = queue[i];
}
cout << endl;
cout << "移动磁道数为:" << steps << endl;
}
void SSTF() {//最短寻道时间优先算法
int steps = 0, move = start, flag, step = 1001;
int* record = new int[N];//记录磁道是否已经访问过
for (int i = 0; i < N; i++)
record[i] = 0; //标记所有磁道都被未访问
cout << "磁头移动轨迹为:" << start;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {//找出寻道时间最短的那个磁道
if (record[j] == 0) {
if (step > abs(queue[j] - move)) {
step = abs(queue[j] - move);
flag = j;
}
}
}
steps += step;
record[flag] = 1; //此磁道已被访问过
move = queue[flag];
step = 1001;
cout<<"->"<<move;
}
cout<<"\n移动磁道数为:"<<steps;
}
void quickSort(int* queue, int low, int high) {//快速排序算法,用于电梯扫描算法中
if (low < high) {
int i = low, j = high;
int temp = queue[i];
while (i < j) {
while (i < j && queue[j] >= temp) {
j--;
}
if (i < j) {
queue[i++] = queue[j];
}
while (i < j && queue[i] <= temp) {
i++;
}
if (i < j) {
queue[j--] = queue[i];
}
}
queue[i] = temp;
quickSort(queue, low, i - 1);
quickSort(queue, i + 1, high);
}
}
void SCAN() {//电梯扫描算法
int flag = N, steps = 0, move = start;
quickSort(queue, 0, N - 1);//快速排序(升序)
for (int i = 0; i < N; i++) {
if (queue[i] > start) {
flag = i;
break;
}
}
int direction = rand() % 2;//随机选择磁头访问方向,0:向左访问,1:向右访问
printf("磁头移动轨迹为:%d", start);
if (direction == 0) {//先向左访问
for (int i = flag - 1; i >= 0; i--) {
steps += abs(queue[i] - move);
move = queue[i];
cout<<"->"<<move;
}
for (int i = N-1; i >=flag; i--) {//从另一端开始访问
steps += abs(queue[i] - move);
move = queue[i];
cout << "->" << move;
}
cout << endl;
cout<<"移动磁道数为:"<<steps;
}
else {//先向右访问
for (int i = flag; i < N; i++) {
steps += abs(queue[i] - move);
move = queue[i];
cout << "->" << move;
}
for (int i = 0; i<flag; i++) { //从另一端开始访问
steps += abs(queue[i] - move);
move = queue[i];
cout << "->" << move;
}
cout << endl;
cout << "移动磁道数为:" << steps;
}
}
int main() {
init(); //初始化数据
cout << endl;
cout<<"*****************先来先服务算法(FCFS)*****************"<<endl;
FCFS();//先来先服务算法
cout << endl;
cout<<"*****************最短寻道时间优先算法(SSTF)*****************"<<endl;
SSTF();//最短寻道时间优先算法
cout << endl;
cout << endl;
cout<<"*****************电梯扫描算法(SCAN)*****************"<<endl;
SCAN(); //电梯扫描算法
release(); //释放资源
}
5、 截屏输出实验结果;
随机生成磁道总数和磁头位置
请求服务的磁道序列
先来先服务算法(FCFS)
最短寻道时间优先算法(SSTF)
电梯扫描算法(SCAN)
6、 根据实验结果与理论课讲述的原理进行实验分析。
1.FCFS算法基于先来先服务原则,不考虑远近,只考虑先后,导致每次磁道请求移动的磁道数大,因此移动的总磁道数远远高于其他两种算法
2.SSTF算法移动的总磁道数最少,但如果是在实际中,操作系统的访问是动态申请的,这就可能导致出现“饥饿”现象,即距离远的磁道得不到服务
3. SCAN算法考避免了SSTF中高度局部化的缺点,在磁道来回扫描,遇到所需的磁道时就进行服务。
4. SSTF与SCAN算法经常会出现移动磁道数相同的情况,因为当磁头初始位置在序列最左边或最右边时移动轨迹是一样的,除此之外,磁头初始磁道位于中间时候也有可能出现移动轨迹相同的情况
六、思考题
1、通过对每个算法进行时间复杂度分析对比,每个算法的效率如何?
1. FCFS算法直接从请求序列读出数据,只需要计算磁头移动的总磁道数,故时间复杂度为O(n)。虽然时间复杂度小,效率最高,但是移动的总磁道数明显大于其他两种算法
2. SSTF算法要求选择的下一个请求距当前磁头所在位置有最小的寻道时间,每次都需要遍历n次获得最小值对应的磁道,一共需要执行n次,故时间复杂度为O(n²)。可能会导致距离磁头较远的请求服务很久才能得到回应
3. SCAN算法调用快速排序对请求队列进行排序,其时间复杂度平均情况为O(nlogn),再根据磁头位置情况,计算出整个算法的时间复杂度为O(nlogn)。SCAN算法弥补了SSTF的缺陷。
2、若所有硬盘全部设计成电子硬盘,哪个磁盘调度算法最合适?
先来先服务算法(FCFS)最合适,因为电子硬盘读取速度极快,且不需要物理寻道。