Lab Week 18
实验内容:硬盘调度。
编写一个 C 程序模拟实现课件 Lecture25 中的硬盘磁头调度算法,包括FCFS、SSTF、SCAN 和 C-LOOK 调度策略。
- 固定一个硬盘柱面数;
- 输入一批随机的硬盘柱面请求序列,计算各个调度策略下的磁头移动平均总距离(假设磁头运动是理想匀速的,可以把移动距离看作是移动时间,将总时间除以请求数得到平均响应时间)。
分析上述实验结果。
磁盘调度
磁盘为现代计算机系统提供大量外存,容量以GB计数,结构如下所示。
每一层称为一个柱面,共有数千个柱面。每个柱面分有若干个扇区。每个扇区有若干个磁道。数据可以理解为储存在某个柱面的某个扇区的某个磁道上。
在通电后磁盘高速旋转每秒约转60~250次。
读取和写入数据时,磁头要移动到对应的柱面,所需时间称为寻道时间
旋转磁头到目标扇区的时间称为选择延迟
本实验仅考虑寻道时间
操作系统的一个重要职责就是有效利用硬件,让磁盘有较快的访问速度和较宽的带宽。
磁盘带宽指一段传输的总字节数除以传输的时间
当程序需要进行磁盘I/O时,将调用系统调用,但磁盘速度远远慢于内存和CPU,磁盘需要建立等待队列,维护多个待处理的请求。
磁头需要根据磁盘调度算法移动和读写信息。
本实验中不考虑磁头的读写时间。
FCFS先来先服务调度算法
按加入顺序处理I/O请求
貌似对所有进程都是公平的
如果有许多进程/请求,则在性能上接近随机调度
即每一次寻道时间的期望为三分之一的柱面数
代码中用数组模拟的FIFO队列实现
关键代码如下
if(!tim1)
{//FCFS算法
while(fifo[h1]==pos1 && h1<=t1)
{// 若到达了目标柱面,就执行读写
h1++;
ans1++;
}
if(h1<=t1)
{
if( fifo[h1]> pos1)
pos1++;
else
pos1--;
}
if(ans1==lenth)
tim1=tim;
}
若当前移动到了目标位置,则处理该读写请求。
(不处理在同一个位置,但是后来的请求)
若队列非空,则以队头为当前目标位置,决定磁头上移还是下移。
SSTF最短寻道时间优先调度算法
SSTF从当前磁头位置选择具有最小寻道时间的请求。
磁头在找到一个目标,完成读写后,从请求队列里找出距离最近的请求作为下一个目标位置。
由于柱面的逻辑结构是个序列,而不是甜甜圈,这个算法更加优先于处理中间的柱面请求。
关键代码如下
if(!tim2)
{
ans2+=c2[pos2];
c2[pos2]=0;
for(int i=0;i<cylinder_num;i++)
{
if(pos2-i>=0 && c2[ pos2-i])
{
pos2--;
break;
}
if(pos2+i<cylinder_num && c2[pos2+i])
{
pos2++;
break;
}
}
if(ans2==lenth)
tim2=tim;
}
若当前磁头所指的柱面是有被请求的,就处理该请求
随后枚举距离,查看最短距离的求请求在哪里,决定磁头上移还是下移
SCAN扫描算法
磁头从磁盘的一端开始,向另一端移动,扫描每一个柱面,经过柱面时处理请求。当到达磁盘的另一端时,磁头移动方向反转,并继续处理。磁头连续来回扫描磁盘。
有延伸的C-SCAN算法,即磁头在移动到另一端时,立即返回至开头,返程时不处理任何请求
关键代码如下
if(!tim3)
{
ans3+=c3[pos3];
c3[pos3]=0;
if(!dir3 && pos3==cylinder_num-1)
dir3=1;
if(dir3 && pos3==0)
dir3=0;
if(dir3)
pos3--;
else
pos3++;
if(ans3==lenth)
tim3=tim;
}
用变量dir维护磁头维护的方向
若dir=0,则磁头向柱面编号增大的方向移动
否则磁头向柱面编号减小的方向移动
若移动到尽头,则改变方向
处理沿途的柱面请求
LOOK调度算法和C-LOOK算法
可以看做SCAN和C-SCAN算法的改进
同样是磁头扫描算法
LOCK中,磁头每次扫描会在最远处的请求处终止,并不会扫描全部柱面
C-LOCK中,每次正向扫描时,磁头移动到正向最远处就停止,返回。
返回时不处理任何请求。返回时同样返回到正向第一个请求所在的柱面出。
实际上返回时不处理请求不会对平均等待时间有较大影响。
但会使得等待时间均匀
代码实现如下
if(dir4==0)
{
ans4+=c4[pos4];
c4[pos4]=0;
int ok=0;
for(int i=pos4+1;i<cylinder_num;i++)
if(c4[i])
ok=1;
if(ok)
pos4++;
else
dir4=1;
}
if(dir4==1 && pos4>0)
pos4--;
if(ans4==lenth)
tim4=tim;
}
dir=1表示磁头反向移动
若磁头前面已经没有请求了,则将磁头方向翻转
若dir=0,磁头正向移动,处理当前位置的请求
再判断磁头后方是否有请求,若有,则磁头继续前进
否则翻转磁头方向
实验结果
#define lenth 200000 // 柱面访问序列长度
#define cylinder_num 10000 // 磁盘柱面数
#define interval 3 // 访问请求间隔
先假设了柱面访问长度为200000
为了增大不同算法间的差距,设置柱面数为10000
若请求之间没有间隔,则无论多少个请求,扫描算法都能在一次扫描出结果
故设置每个请求在上一个请求到达后3个时间单位到达
结果如下
显然FCFS算法采用先来先服务原则,而生成的柱面访问序列是完全随机的,根据数学知识,随机两个柱面的期望距离为1/3柱面数
从实验结果可以看出,FCFS的平均响应时间确实约为柱面数的三分之一,效果最差。虽然很慢,也许能保证某种程度的公平
SSIF算法每次寻找最近的柱面请求,实际轨迹可能行走出一个之字形。
但在全部请求都已经进入队列后,移动路径长度不超过两倍柱面数,就能处理掉所有的请求。
故平均响应时间为3.06,略大于请求的间隔,因为Z字型效应,算法性能第二差
SCAN算法每次扫描一次就能完成全部请求,在全部请求进入队列后,用不超过,但接近10000的时间就能处理所有请求。
故平均响应时间为3.0497,略大于请求的间隔。因为在最后时,磁头大概率会停止中间,使得几乎要再扫一遍才能完成所有请求,性能略次于C-LOCK
C-LOCK算法中,由于SCAN算法在磁头返回时,有重复走过来时的路,相当于走了一段无用的路,与C-LOCK的单向扫描几乎等价
但C-LOCK走到最远的请求就会停下,走的总路程比SCAN短。
故算法性能最优,时间3.0491,略多于请求的载入间隔。