1 上机实验一 磁盘移臂调度算法实验
在本实验中,我们模拟了FCFS、SSTF、SCAN、C-SCAN以及LOOK五种调度算法的实现。同时基于这五种调度算法,我们将在分析中给出各种算法的比较。
1.1 实验代码
首先,我们需要在虚拟机下建立相应的文件:
dask.h文件:
/*
* Filename : dask.h
* copyright : (C)
: 声明磁盘移臂调度类
*/
#include <stdlib.h>
#include <iostream>
#include <iomanip>
#include <malloc.h>
class DiskArm{
public:
DiskArm();
~DiskArm();
void InitSpace(char * MethodName); //初始化寻道记录
void Report(void); // 报告算法执行情况
void Fcfs(void); //先来先服务算法
void Sstf(void); //最短寻道时间优先算法
void Scan(void); //电梯调度算法
void CScan(void); //均匀电梯调度算法
void Look(void); //LOOK 调度算法
private:
int *Request ; //磁盘请求道号
int *Cylinder; //工作柱面道号号
int RequestNumber; //磁盘请求数
int CurrentCylinder; //当前道号
int SeekDirection; //磁头方向
int SeekNumber; //移臂总数
int SeekChang; //磁头调头数
};
dask.cc文件:
/*
* Filename : dask.cc
* copyright :
: 磁盘移臂调度算法
* Function
*/
#include "dask.h"
using namespace std;
DiskArm::DiskArm(){
int i;
//输入当前道号
cout << "Please input Current cylinder :" ;
cin >> CurrentCylinder;
//磁头方向,输入 0 表示向小道号移动,1 表示向大道号移动
cout << "Please input Current Direction (0/1) :" ;
cin >> SeekDirection;
//输入磁盘请求数,请求道号
cout << "Please input Request Numbers :" ;
cin >> RequestNumber;
cout << "Please input Request cylinder string :";
Request = new int[sizeof(int) * RequestNumber];
Cylinder = new int[sizeof(int) * RequestNumber];
for (i = 0; i < RequestNumber; i++)
cin >> Request[i];
}
DiskArm::~DiskArm(){
}
//初始化道号,寻道记录
void DiskArm::InitSpace(char * MethodName)
{
int i;
cout << endl << MethodName << endl;
SeekNumber = 0;
SeekChang = 0;
for (i = 0; i < RequestNumber; i++)
Cylinder[i] = Request[i];
}
// 统计报告算法执行情况
void DiskArm::Report(void){
cout << endl;
cout << "Seek Number: " << SeekNumber << endl;
cout << "Chang Direction: " << SeekChang << endl << endl;
}
//先来先服务算法
void DiskArm::Fcfs(void)
{
int Current = CurrentCylinder;
int Direction = SeekDirection;
InitSpace("FCFS");
cout << Current;
for(int i=0; i<RequestNumber; i++){
if(((Cylinder[i] >= Current) && !Direction)
||((Cylinder[i] < Current) && Direction)){
//需要调头
SeekChang++; //调头数加 1
Direction = !Direction ; //改变方向标志
//报告当前响应的道号
cout << endl << Current << " -> " << Cylinder[i];
}
else //不需调头,报告当前响应的道号
cout << " -> " << Cylinder[i] ;
//累计寻道数,响应过的道号变为当前道号
SeekNumber += abs(Current -Cylinder[i]);
Current = Cylinder[i];
}
//报告磁盘移臂调度的情况
Report();
}
//最短寻道时间优先算法
void DiskArm::Sstf(void)
{
int Shortest;
int Distance = 999999 ;
int Direction = SeekDirection;
int Current = CurrentCylinder;
InitSpace("SSTF");
cout << Current;
for(int i=0; i<RequestNumber; i++){
//查找当前最近道号
for(int j=0; j<RequestNumber; j++){
if(Cylinder[j] == -1) continue; //-1 表示已经响应过了
if(Distance > abs(Current-Cylinder[j])){
//到下一道号比当前距离近,下一道号为当前距离
Distance = abs(Current-Cylinder[j]);
Shortest = j;
}
}
if((( Cylinder[Shortest] >= Current) && !Direction)
||(( Cylinder[Shortest] < CurrentCylinder) && Direction)){
//需要调头
SeekChang++; //调头数加 1
Direction = !Direction ; //改变方向标志
//报告当前响应的道号
cout << endl << Current << " -> " << Cylinder[Shortest];
}
else //不需调头,报告当前响应的道号
cout << " -> " << Cylinder[Shortest] ;
//累计寻道数,响应过的道号变为当前道号
SeekNumber += abs(Current -Cylinder[Shortest]);
Current = Cylinder[Shortest];
//恢复最近距离,销去响应过的道号
Distance = 999999;
Cylinder[Shortest] = -1;
}
Report();
}
//辅助 排序函数
void sort(int *a,int n)
{
for (int i=0;i<n-1;i++){
for(int j=0;j<n-i-1;j++){
if(a[j]>a[j+1]){
int temp=a[j+1];
a[j+1]=a[j];
a[j]=temp;
}
}
}
}
//电梯调度算法
void DiskArm::Scan(void){
int Current = CurrentCylinder;
int Direction = SeekDirection;
InitSpace("SCAN");
cout << Current;
int point=0;
for(int i=0;i<RequestNumber;i++){
if (Cylinder[i]<=Current) point++;
}
sort(Cylinder,RequestNumber);
// for(int i=0;i<RequestNumber;i++){cout<<Cylinder[i]<<" ";}
// cout<<endl;
if(Direction==0){
for(int i= point-1;i>=0;i--){
cout<<"->"<<Cylinder[i]<<" ";
}
cout<<"->"<<0;
cout<<endl;
SeekChang++;
SeekNumber += abs(Current -0);
cout<<"0";
for(int i=point;i<RequestNumber;i++){
cout<<"->"<<Cylinder[i]<<" ";
}
cout<<endl;
SeekNumber += abs(9999 -0);
}
else if(Direction==1){
for(int i=point;i<RequestNumber;i++){
cout<<"->"<<Cylinder[i]<<" ";
} cout<<"->"<<"9999";
cout<<endl;
SeekNumber += abs(9999 -Current);
SeekChang++;
cout<<"9999";
for(int i= point-1;i>=0;i--){
cout<<"->"<<Cylinder[i]<<" ";
}
SeekNumber += abs(9999 -0);
}
Report();
}
//均匀电梯调度算法
void DiskArm::CScan(void){
int Current = CurrentCylinder;
int Direction = SeekDirection;
InitSpace("CSCAN");
cout << Current;
int point=0;
for(int i=0;i<RequestNumber;i++){
if (Cylinder[i]<=Current) point++;
}
sort(Cylinder,RequestNumber);
if(Direction==0){
for(int i= point-1;i>=0;i--){
cout<<"->"<<Cylinder[i]<<" ";
}
cout<<"->"<<"0";
cout<<endl;
SeekChang++;
SeekNumber += abs(Current -0);
cout<<Cylinder[RequestNumber];
//for(int i=point;i<RequestNumber;i++){
for(int i=RequestNumber-1;i>=point;i--){
cout<<"->"<<Cylinder[i]<<" ";
}
cout<<endl;
SeekChang++;
SeekNumber += abs(9999 -Cylinder[point]);
}
else if(Direction==1){
for(int i=point;i<RequestNumber;i++){
cout<<"->"<<Cylinder[i]<<" ";
} cout<<"->"<<"9999";
cout<<endl;
SeekNumber += abs(9999 -Current);
SeekChang++;
cout<<"0";
for(int i=0;i<=point-1;i++){
cout<<"->"<<Cylinder[i]<<" ";
}
SeekNumber += abs(Cylinder[point-1] -0);
}
Report();
}
//LOOK 调度算法
void DiskArm::Look(void)
{
//初始化当前位置和运行方向
int Current = CurrentCylinder;
int Direction = SeekDirection;
//传入初始化 算法名字和访问请求序列
InitSpace("LOOK");
//显示当前位置
cout << Current;
int point=0;
//使用LOOK算法 在到达requestnumber个数时代表着读到末尾了,应该掉头读取
for(int i=0;i<RequestNumber;i++){//统计磁道号小于等于当前磁道号的个数
if (Cylinder[i]<=Current) point++;
}
sort(Cylinder,RequestNumber);
if(Direction==0){//代表往左走
for(int i= point-1;i>=0;i--){
cout<<"->"<<Cylinder[i]<<" ";
}
cout<<endl;
//磁头变动顺序
SeekChang++;
//磁头移动数 通过计算abs得到
SeekNumber += abs(Current -Cylinder[0]);
cout<<Cylinder[RequestNumber-1];
for(int i=RequestNumber-2;i>=point;i--){
//显示读取顺序
cout<<"->"<<Cylinder[i]<<" ";
}
cout<<endl;
SeekChang++;
SeekNumber += abs(Cylinder[RequestNumber]-Cylinder[point]);
}
//往右走
else if(Direction==1){
for(int i=point;i<RequestNumber;i++){
cout<<"->"<<Cylinder[i]<<" ";
}
cout<<endl;
SeekNumber += abs( Cylinder[RequestNumber]-Current);
SeekChang++;
cout<<Cylinder[0];
for(int i=1;i<=point-1;i++){
cout<<"->"<<Cylinder[i]<<" ";
}
SeekChang++;
SeekNumber += abs(Cylinder[point-1] -Cylinder[0]);
}
Report();
}
//程序启动入口
int main(int argc,char *argv[]){
//建立磁盘移臂调度类
DiskArm *dask = new DiskArm();
//比较和分析 FCFS 和 SSTF 两种调度算法的性能
dask->Fcfs();
dask->Sstf();
dask->Scan();
dask->CScan();
dask->Look();
}
接着编译makefile文件,并输入相应指令,即可完成编译与运行。
1.2 运行结果
我们利用这几种算法进行模拟,得到的实验结果如下:
FCFS算法和SSTF算法实现:
SCAN算法、C-SCAN算法和LOOK算法实现:
1.3 算法的比较
1.3.1 FCFS算法
FCFS算法根据进程请求访问磁盘的先后顺序进行调度,这是一种最简单的调度算法,优点是具有公平性。但倘若有大量进程使用磁盘,则这种算法在性能上往往接近于随即调度,性能较差。
因此,FCFS适用于少量进程使用磁盘的情况。
1.3.2 SSTF算法
SSTF算法选择调度处理的磁道是与当前磁头距离最近的磁道,以便于使得每次寻找的时间最短,但这并不能保证总寻找时间最短。但是相较于FCFS算法,SSTF算法的性能有了提高。但是该算法会频繁请求磁头附近的磁道,导致原理磁头的磁道迟迟得不到访问。因此,SSTF算法存在“饥饿”现象,这也是SSTF算法的缺陷之一。
因此,SSTF适用于进程集中于某一磁道范围内的情况,以避免出现“饥饿”
的情况。
1.3.3 SCAN算法
SCAN算法在磁头当前移动方向上选择与当前磁头所在磁道距离最近的请求作为下一次服务的对象,又被成为“电梯调度算法”。由于SCAN算法对最近扫描过的区域不公平,使得它们难以被下一次访问,因此它在访问局部性方面不如FSFC算法和SSTF算法。
1.3.4 C-SCAN算法
C-SCAN算法在SCAN算法的基础上规定磁头单向移动来提供服务,同时回返时直接快速移动到起始段而不服务任何请求,消除了SCAN算法偏向于处理那些接近最里或者最外的磁道访问请求。
1.3.5 LOOK算法、C-LOOK算法
SCAN算法和C-SCAN算法存在不必要的开销,即:每次必须移动到磁道的最里或者最外的磁道才可以返回。因此,将SCAN算法改进为LOOK算法、将C-SCAN算法改进为C-LOOK算法,避免了每次必须移动到磁道的最里或者最外的磁道才可以返回的问题,减小了时间开销,一定程度上提高了效率。