一、实验目的
编程模拟实现磁盘调度的常用算法或调试分析相关磁盘调度程序,加深对磁盘调度常用算法的理解和实现技巧
二、实验环境
VS2017+PC
三、实验内容
1.自定义磁盘调度相关的数据结构;
2、依据先来先服务算法(FCFS)、最短寻道优先算法(SSTF)、扫描(SCAN,也称电梯)算法的原理,编写对应函数,模拟系统的磁盘调度服务;
3、为了更好地模拟和评价算法的性能,随机产生需寻道的磁道序列,以磁道序列的首磁道为磁头的当前位置;在SCAN算法中,允许用户指定当前寻道方向;
4.统计以上算法总寻道次数数和平均寻道距离;
5、比较/分析以上算法的寻道性能,并作出自己的评价。
四、实验步骤
- 在主函数中实验对四个算法的调用,在主函数中设置了五个选择,选择一位先来先服务算法,选择二是最短寻道算法,选择三是扫描算法,选择四是循环扫面算法,选择五是退出,然后在根据算法写四个返回函数。
- 先来先服务算法:这是一种比较简单的磁盘调度算法。它根据进程请求访问磁盘的先后次序进行调度。此算法的优点是公平、简单,且每个进程的请求都能依次得到处理,不会出现某一进程的请求长期得不到满足的情况。此算法由于未对寻道进行优化,在对磁盘的访问请求比较多的情况下,此算法将降低设备服务的吞吐量,致使平均寻道时间可能较长,但各进程得到服务的响应时间的变化幅度较小。
- 最短寻道优先算法:该算法选择这样的进程,其要求访问的磁道与当前磁头所在的磁道距离最近,以使每次的寻道时间最短,该算法可以得到比较好的吞吐量,但却不能保证平均寻道时间最短。其缺点是对用户的服务请求的响应机会不是均等的,因而导致响应时间的变化幅度很大。在服务请求很多的情况下,对内外边缘磁道的请求将会无限期的被延迟,有些请求的响应时间将不可预期。
- 扫描算法不仅考虑到欲访问的磁道与当前磁道的距离,更优先考虑的是磁头的当前移动方向。例如,当磁头正在自里向外移动时,扫描算法所选择的下一个访问对象应是其欲访问的磁道既在当前磁道之外,又是距离最近的。这样自里向外地访问,直到再无更外的磁道需要访问才将磁臂换向,自外向里移动。这时,同样也是每次选择这样的进程来调度,即其要访问的磁道,在当前磁道之内,从而避免了饥饿现象的出现。由于这种算法中磁头移动的规律颇似电梯的运行,故又称为电梯调度算法。此算法基本上克服了最短寻道时间优先算法的服务集中于中间磁道和响应时间变化比较大的缺点,而具有最短寻道时间优先算法的优点即吞吐量较大,平均响应时间较小,但由于是摆动式的扫描方法,两侧磁道被访问的频率仍低于中间磁道。
- 循环扫描算法是对扫描算法的改进。如果对磁道的访问请求是均匀分布的,当磁头到达磁盘的一端,并反向运动时落在磁头之后的访问请求相对较少。这是由于这些磁道刚被处理,而磁盘另一端的请求密度相当高,且这些访问请求等待的时间较长,为了解决这种情况,循环扫描算法规定磁头单向移动。例如,只自里向外移动,当磁头移到最外的被访问磁道时,磁头立即返回到最里的欲访磁道,即将最小磁道号紧接着最大磁道号构成循环,进行扫描。
五、总结
通过这次试验,我们清楚的了解到磁盘调度的详细过程和四种调度算法(先来先服务算法;最短寻道时间优先算法;扫描算法;循环扫描算法)以及四种调度算法之间的差异和共性,同时,也看到了经过优化的算法会带来的好处!在实验过程中,也遇到了不少问题,在实现扫描算法时出现了问题!通过和同学的讨论,发经过调整后,程序执行无误!以后,在实现代码的过程中,一定会更加小心,防止出现低级错误导致程序出错!
六、代码
// Test2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
using namespace std;
#define maxsize 100 //定义最大数组域
void FIFO(int array[],int m)//先进先出调度算法
{
int sum = 0;
int now; //当前的磁道
float avg;
cout << "请输入当前的磁道:" << endl;
cin >> now;
cout << "FIFO的磁盘调度结果为:" << endl;
cout << now << endl;
for (int i = 0; i < m; i++)
cout << array[i]<<'\t';
sum = abs(now - array[0]);
for (int j = 1; j < m; j++)
sum += abs(array[j] - array[j - 1]);
avg = (float)sum / m; //计算平均寻道长度
cout << endl;
cout << "移动的总道数为" <<sum<< endl;
cout << "平均寻道长度为:" <<avg<< endl;
}
void SSTF(int array[], int m) //最短服务时间优先调度算法
{
int temp;
int k = 1;
int now, l, r;
int sum = 0;
float avg;
for (int i = 0; i < m; i++)
{
for (int j = i + 1; j < m; j++) //对磁道号进行从小到大排列
{
if (array[i] > array[j])//两磁道号之间比较
{
temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
}
for (int i = 0; i < m; i++) //输出排序后的磁道号数组
cout << array[i] << '\t';
cout << endl;
cout<<" 请输入当前的磁道: "<<endl;
cin >> now;
cout<<"SSTF磁盘调度结果: "<<endl;
if (array[m - 1] <= now)//判断整个数组里的数是否都小于当前磁道号
{
for (int i = m - 1; i >= 0; i--) //将数组磁道号从大到小输出
cout << array[i] << '\t';
sum = now - array[0];//计算移动距离
}
else if (array[0] >= now)//判断整个数组里的数是否都大于当前磁道号
{
for (int i = 0; i < m; i++) //将磁道号从小到大输出
cout << array[i] << '\t';
sum = array[m - 1] - now;//计算移动距离
}
else
{
while (array[k] < now)//逐一比较以确定 K 值
{
k++;
}
l = k - 1;
r = k;
//确定当前磁道在已排的序列中的位置
while ((l >= 0) && (r < m))
{
if ((now - array[l]) <= (array[r] - now))//判断最短距离
{
cout<< array[l]<<'\t';
sum += now - array[l];//计算移动距离
now = array[l];
l = l - 1;
}
else
{
cout<<array[r]<<endl;
sum += array[r] - now;//计算移动距离
now = array[r];
r = r + 1;
}
}
if (l = -1)
{
for (int j = r; j < m; j++)
{
cout<<array[j]<<endl;
}
sum += array[m - 1] - array[0];//计算移动距离
}
else
{
for (int j = l; j >= 0; j--)
{
cout<<array[j]<<endl;
}
sum += array[m - 1] - array[0];//计算移动距离
}
}
avg = (float)sum / m;
cout<<"移动的总道数"<<sum<<endl;
cout<<"平均寻道长度:"<<avg<<endl;
}
void SCAN(int array[], int m) //扫描算法
{
int sum = 0;
for (int i = 0; i < m; i++)
{
for (int j = i + 1; j < m; j++) //对磁道号进行从小到大排列
{
if (array[i] > array[j])//两磁道号之间比较
{
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
}
for (int i = 0; i < m; i++)
{
cout<<array[i]<<'\t';
}
cout << endl;
cout<<"请输入当前的磁道号: "<<endl;
int now;
cin>>now;
cout<<"SCAN磁盘调度结果:"<<endl;
int pos;
for (int i = 0; i < m; i++)
{
if (array[i] >= now)
{
pos = i;
sum += abs(array[i] - now);
break;
}
}
for (int i = pos; i < m; i++)
{
if (i != pos)
sum += abs(array[i] - array[i - 1]);
cout<<array[i]<<'\t';
}
if (pos >= 1)
sum += abs(array[m - 1] - array[pos - 1]);
for (int i = pos - 1; i >= 0; i--)
{
if (i)
sum += abs(array[i] - array[i - 1]);
cout<<array[i]<<'\t';
}
cout << endl;
cout << "移动的总道数:" << sum << endl;
cout<<"平均寻道长度:"<<1.0*sum / m<<endl;
}
void CSCAN(int array[], int m) //循环扫描算法
{
int sum = 0;
for (int i = 0; i < m; i++)
{
for (int j = i + 1; j < m; j++) //对磁道号进行从小到大排列
{
if (array[i] > array[j])//两磁道号之间比较
{
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
}
for (int i = 0; i < m; i++)
{
cout<<array[i]<<'\t';
}
cout << endl;
cout<<"请输入当前的磁道: "<<endl;
int now;
cin>>now;
cout<<"CSCAN磁盘调度结果:"<<endl;
int pos;
for (int i = 0; i < m; i++)
{
if (array[i] >= now)
{
pos = i;
sum += abs(array[i] - now);
break;
}
}
for (int i = pos; i < m; i++)
{
if (i != pos)
sum += abs(array[i] - array[i - 1]);
cout<<array[i]<<'\t';
}
if (pos >= 1)
sum += abs(array[m - 1] - array[0]);
for (int i = 0; i < pos; i++)
{
if (i)
sum += abs(array[i] - array[i - 1]);
cout<<array[i]<<'\t';
}
cout << endl;
cout << "移动的总道数:" << sum << endl;
cout<<"平均寻道长度:"<<1.0*sum / m<<endl;
}
int main()
{
int choice;
int count;
int m = 0;
int cidao[maxsize]; //定义磁道号数组
int b;
cout << "情输入磁盘数量:" << endl;
cin >> b;
cout << "请输入磁盘序列:" << endl;
for (int i = 0; i < b; i++)
{
cin >> cidao[i];
}
cout << "磁盘读取结果是:" << endl;
for (int i = 0; i < b; i++)
{
cout << cidao[i]<<'\t';
}
count = b;
cout << endl;
while (1)
{
cout << "------------磁盘选择算法-----------" << endl;
cout << "------------1.先进先出算法---------" << endl;
cout << "------------2.最短服务时间优先算法-" << endl;
cout << "------------3.扫描算法-------------" << endl;
cout << "------------4.循环扫描算法---------" << endl;
cout << "------------5.退出-----------------" << endl;
cout << "-------------请输入选择------------" << endl;
cin >> choice;
if (choice > 5)
break;
switch (choice)
{
case 1:
FIFO(cidao, count);
break;
case 2:
SSTF(cidao, count);
break;
case 3:
SCAN(cidao, count);
break;
case 4:
CSCAN(cidao, count);
break;
case 5:
exit(0);
}
}
return 0;
}
// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单
// 入门使用技巧:
// 1. 使用解决方案资源管理器窗口添加/管理文件
// 2. 使用团队资源管理器窗口连接到源代码管理
// 3. 使用输出窗口查看生成输出和其他消息
// 4. 使用错误列表窗口查看错误
// 5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
// 6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件