Lab Week 18 实验报告

实验内容:硬盘调度

  • 编写一个 C 程序模拟实现课件 Lecture25 中的硬盘磁头调度算法,包括

    • FCFS、SSTF、SCAN 和 C-LOOK 调度策略。
    • 固定一个硬盘柱面数;
    • 输入一批随机的硬盘柱面请求序列,计算各个调度策略下的磁头移动平均总距离 (假设磁头运动是理想匀速的,可以把移动距离看作是移动时间,将总时间除以请求数得到平均响应时间)。
  • 分析上述实验结果。

I. 硬盘磁头调度算法

由于内存通常太小而且不能永久保存所有数据和程序,因此计算机系统必须提供外存来备份内存。现代计算机系统采用磁盘(硬盘)作为信息(程序与数据)的主要在线存储介质。换句话说,硬盘或磁盘为现代计算机系统提供大量外存。

磁盘是表面涂有磁性物质的物理盘片,通过磁头(导体线圈)从磁盘存取数据,在读/写期间,磁头固定,磁盘在下面高速旋转。磁盘盘面上的数据存储在一组同心圆中,称为磁道。每个磁道和磁头一样宽,一个盘面上有上千个磁道。磁道又分为几百个扇区,每个扇区固定存储大小,因此越往内的扇区密度越高。

磁盘地址由(柱面号,盘面号,扇区号)表示。

操作系统的职责之一是有效使用硬件。对于磁盘驱动器,满足这个要求具有较快的访问速度和较宽的磁盘带宽。

对于磁盘,访问时间包括两个主要部分:

  • 寻道时间:是磁臂移动磁头到包含目标扇区的柱面的时间;
  • 旋转延迟:是磁盘旋转目标扇区到磁头下的额外时间;

在这部分,我们针对寻道时间来进行优化,通过不同的磁头调度算法,分析优化的情况。

1. 先来先服务(First Come First Served, FCFS)算法

FCFS算法根据进程请求访问磁盘的先后顺序进行调度,这是最简单的磁盘调度算法,虽然这种算法比较公平,但是它通常并不提供最快的服务。

实现代码:

//设置磁道请求
void set_request(int *cylinders, int *request, int req_num){for(int i = 0; i < req_num; i++){int req_id = request[i];cylinders[req_id]++; //对应的磁道请求数加1}
}

代码说明:

该函数对磁道表cylinders的请求进行设置,如果该磁道存在请求,那么将其对应的表项值加一,以此类推;

void FCFS(int head, int *request, int *cylinders, int req_num){printf("===============FCFS=============\n");int move_sum = 0;memset(cylinders, 0, CYLINDER_MAX * sizeof(int));set_request(cylinders, request, req_num);//设置磁道请求printf("Head location: %d\n", head);printf("Processing sequence: ");printf("%d ", head);for(int i = 0; i < req_num; i++){int req_id = request[i];printf("%d ", req_id);cylinders[req_id]--;move_sum += abs(head - req_id); //计算移动距离head = req_id; //磁头移动}printf("\nAverage total distance of head movement = %d\n", move_sum);printf("Average average response time = %f\n\n", (double)(move_sum/req_num));}

代码说明:

根据FCFS调度算法的原理,直接对请求序列从头到尾进行处理,并且计算磁头的移动距离和平均响应时间;

实验结果:

the queue with requests for cylinders: 98 183 37 122 14 124 65 67

the head's position of cylinder: 53

2. 最短寻道时间优先(Shortest Seek Time First, SSTF)算法

SSTF总是选择离当前磁头所在磁道最近的磁道,以便每次寻找的时间最短,在移动磁头到别处以便处理其他请求之前,处理靠近当前磁头位置的所有请求可能较为合理。

这种算法的缺陷是,若某磁头附近频繁地被添加请求,那么磁头会长时间在这附近工作,导致更远的磁道无期限地延迟,即“饥饿”。

实现代码:

void SSTF(int head, int *request, int *cylinders, int req_num){printf("===============SSTF=============\n");int move_sum = 0;int dis_list[req_num];int dis_idx[req_num];int init_head = head;for(int i = 0; i < req_num; i++){int dis = abs(head - request[i]);dis_list[i] = dis;dis_idx[i] = i;}memset(cylinders, 0, CYLINDER_MAX * sizeof(int));set_request(cylinders, request, req_num);printf("Head location: %d\n", head);//对dis_list从小到大进行排序,作为磁道请求序列for(int i = 0; i < req_num - 1; i++){for(int j = 0; j < req_num - i - 1; j++){if(dis_list[j] > dis_list[j+1]){int temp = dis_list[j];int temp_idx = dis_idx[j];dis_list[j] = dis_list[j+1];dis_idx[j] = dis_idx[j+1];dis_list[j+1] = temp;dis_idx[j+1] = temp_idx;} }}printf("Processing sequence: ");printf("%d ", head);for(int i = 0; i < req_num; i++){int req_id = request[dis_idx[i]];printf("%d ", req_id);cylinders[req_id]--;move_sum += abs(head - req_id);head = req_id;}printf("\nAverage total distance of head movement = %d\n", move_sum);printf("Average average response time = %f\n\n", (double)(move_sum/req_num));}

代码说明:

根据SSTF算法的原理,需要优先处理离磁头最近的请求,因此利用冒泡排序对磁头与请求的距离从小到大进行排序,距离记录在dis_list中,对应的请求的下标记录在dis_idx中,方便在排序之后取出请求的磁道数。

实验结果

the queue with requests for cylinders: 98 183 37 122 14 124 65 67

the head's position of cylinder: 53

在SSTF调度策略中,输入8个磁道请求序列,指定磁头初始位置为53,最后得到磁头平均移动总距离为236,平均响应时间为29;

与FCFS调度策略相比,SSTF的平均移动总距离和平均响应时间均更优;

3. SCAN

对于扫描算法,磁臂从磁盘的一端开始,向另一端移动;在移过每个柱面时,处理请求。当到达磁盘的另一端时,磁头移动方向反转,并继续处理。磁头连续来回扫描磁盘。SCAN 算法有时称为电梯算法,因为磁头的行为就像大楼里面的电梯,先处理所有向上的请求,然后再处理相反方向的请求。

实现代码:

void SCAN(int head, int *request, int *cylinders, int req_num, int dir){if(dir != 1 && dir != 0){printf("Direction Error\n");return;}printf("===============SCAN=============\n");int move_sum = 0;int dis_list[req_num];int dis_idx[req_num];int pre_head = head;for(int i = 0; i < req_num; i++){int dis = abs(head - request[i]);dis_list[i] = dis;dis_idx[i] = i;}memset(cylinders, 0, CYLINDER_MAX * sizeof(int));set_request(cylinders, request, req_num);printf("Head location: %d\n", head);printf("Head moving sequence: ");printf("%d ", head);while(head >= 0 && head < CYLINDER_MAX){while(cylinders[head] > 0){printf("%d ", head);move_sum += abs(pre_head - head);pre_head = head;cylinders[head]--;}if(dir == 0) head--;else head++; }if(head == -1) head++;else if(head == CYLINDER_MAX) head--;//移动到磁道尽头后, pre_head修改为head的位置,以便磁头换方向移动if(pre_head != head){printf("%d ", head);move_sum += abs(pre_head - head);pre_head = head;}if(dir == 1) dir = 0;else dir = 1;//反向移动磁头while(head >= 0 && head < CYLINDER_MAX){while(cylinders[head] > 0){printf("%d ", head);move_sum += abs(pre_head - head);pre_head = head;cylinders[head]--;}if(dir == 0) head--;else head++; }printf("\nAverage total distance of head movement = %d\n", move_sum);printf("Average average response time = %f\n\n", (double)(move_sum/req_num));}

代码说明:

根据SCAN调度算法的原理,通过while循环在磁道内让磁头按指定的方向进行移动,并且处理其中的请求,直到到达记录的磁道的尽头,之后调转磁头移动方向继续移动磁头,同样通过while循环来实现;

实验结果:

Head location: 100

Head moving sequence: 55 58 39 18 90 160 150 38 184

Head moving direction: right

在SCAN调度策略中,输入9个磁道请求序列,指定磁头初始位置为100,磁头向右移动(磁道号增大的方向),最后得到磁头平均移动总距离为280,平均响应时间为31;

与FCFS和SSTF调度策略相比,SCAN的平均移动总距离和平均响应时间均更优;

4. C-LOOK

基于SCAN算法,C-LOOK移动磁头从磁盘一端到磁盘另一端(磁臂只需移到一个方向的最远请求为止),并且处理行程上的请求,然而,当磁头到达另一端时,它立即返回到磁盘另一端最远的请求,而并不处理任何回程上的请求,然后从该最远的请求开始,继续往同一方向移动磁盘处理请求。

实现代码:

void C_LOOK(int head, int *request, int *cylinders, int req_num, int dir){if(dir != 1 && dir != 0){printf("Direction Error\n");return;}printf("===============C-LOOK=============\n");int move_sum = 0;int pre_head = head;int left = 0, right = 0;//记录最远两端的请求int flag = 0;memset(cylinders, 0, CYLINDER_MAX * sizeof(int));set_request(cylinders, request, req_num);//获取最远两端的请求left和rightfor(int i = 0; i < CYLINDER_MAX; i++){if(cylinders[i] && !flag) {left = i;flag = 1;}if(flag && cylinders[i]){right = i;}}printf("Left Bound: %d, Right Bound: %d\n", left, right);printf("Head location: %d\n", head);printf("Head moving sequence: ");printf("%d ", head);while(head >= 0 && head < CYLINDER_MAX){//当磁头到达最远端的请求if(head == right && dir){ cylinders[head]--;break;}if(head == left && !dir) {cylinders[head]--;break;}while(cylinders[head] > 0){printf("%d ", head);move_sum += abs(pre_head - head);pre_head = head;cylinders[head]--;}//磁头按指定方向移动if(dir == 0) head--;else head++; }// 移动到磁道尽头后, pre_head修改为head的位置,以便磁头换方向移动if(pre_head != head){printf("%d ", head);move_sum += abs(pre_head - head);pre_head = head;}//直接移动到另一端最远的请求,过程中不处理请求if(dir == 1){head = left;cylinders[head]--;}else{head = right;cylinders[head]--;}printf("%d ", head);move_sum += abs(pre_head - head);pre_head = head;//磁头继续沿着最初指定的方向移动while(head >= 0 && head < CYLINDER_MAX){while(cylinders[head] > 0){printf("%d ", head);move_sum += abs(pre_head - head);pre_head = head;cylinders[head]--;}if(dir == 0) head--;else head++; }printf("\nAverage total distance of head movement = %d\n", move_sum);printf("Average average response time = %f\n\n", (double)(move_sum/req_num));
}

代码说明:

根据C-LOOK调度算法的原理,首先记录最远两端的请求,保存在变量left和right中,随后通过while循环在磁道内让磁头按指定的方向进行移动,并且处理其中的请求,直到到达记录的最远请求(按移动方向而定),之后将磁头移动到另外一端最远的请求处,从该请求开始继续按最初指定的方向移动磁头,同样通过while循环来实现;

实验结果:

Head location: 100

Head moving sequence: 55 58 39 18 90 160 150 38 184

Head moving direction: right

在C-LOOK调度策略中,输入9个磁道请求序列,指定磁头初始位置为100,磁头向右移动(磁道号增大的方向),最后得到磁头平均移动总距离为322,平均响应时间为35;

与FCFS和SSTF调度策略相比,C-LOOK的平均移动总距离和平均响应时间比FCFS和SSTF更优,但是比SCAN调度策略更差;

输入的柱面请求序列具有局部性分布:

Head location: 25

Head moving sequence: 20 30 12 20 30 12 20 30 12 30

Head moving direction: right

请求序列工作集 = {12, 20, 30}

从结果可知,C-LOOK的性能最优,SCAN的性能最差,从直观上来看,由于请求的序列的集中在12,20,30,而SCAN调度算法每次都需要将磁头移动到磁道尽头,这样就导致了移动距离相比其它三个算法更大;而C-LOOK中,磁头移动到请求序列的最远请求就停止,并且处理完该磁道的所有请求后再移动到其它请求处,所以大大减少了磁头移动的距离;SSTF的表现也相对较优;

Head location: 50

Head moving sequence: 10 100 5 10 100 5 10 100 5 10 100 5

Head moving direction: right

请求序列工作集 = {5, 10, 100}

在这个带有局部性的柱面请求序列中,工作集为 {5, 10, 100},可以看到请求5和100之间的距离相对较大;

四种磁头调度算法中,SSTF的性能最优,因为在请求之间距离相对较远的情况下,SSTF总是选择离当前磁头最近的请求进行处理,因此避免了远距离的移动,进而提高性能;

可以看到FCFS的性能最差,总直观上来说,因为请求序列中磁道100和5的请求总是相邻出现的,而它们距离相对较大,所以磁头移动距离就大幅提升了;

II. FCFS、SSTF、SCAN 和 C-LOOK 调度策略的比较

在下表中对四种磁头调度算法的优缺点进行总结:

优点 缺点
FCFS 公平、简单 平均寻道距离大,仅应用在磁盘I/O较少的场合
SSTF 性能比FCFS好 不能保证平均寻道时间最短(TSP问题)、容易产生“饥饿”现象
SCAN 寻道性能较好、可避免”饥饿“现象 不利于远离磁头一端的访问请求
C-LOOK 消除了对两端磁道请求的不公平 ------------------------------------------------------------

完整代码:

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
#include<math.h>
#define CYLINDER_MAX 200 //最大磁道数
#define REQUEST_MAX 20  //最大请求数//设置磁道请求
void set_request(int *cylinders, int *request, int req_num){for(int i = 0; i < req_num; i++){int req_id = request[i];cylinders[req_id]++; //对应的磁道请求数加1}
}void FCFS(int head, int *request, int *cylinders, int req_num){printf("===============FCFS=============\n");int move_sum = 0;memset(cylinders, 0, CYLINDER_MAX * sizeof(int));set_request(cylinders, request, req_num);printf("Head location: %d\n", head);printf("Processing sequence: ");printf("%d ", head);for(int i = 0; i < req_num; i++){int req_id = request[i];printf("%d ", req_id);cylinders[req_id]--;move_sum += abs(head - req_id);head = req_id;}printf("\nAverage total distance of head movement = %d\n", move_sum);printf("Average average response time = %f\n\n", (double)(move_sum/req_num));}void SSTF(int head, int *request, int *cylinders, int req_num){printf("===============SSTF=============\n");int move_sum = 0;int dis_list[req_num];int dis_idx[req_num];int init_head = head;for(int i = 0; i < req_num; i++){int dis = abs(head - request[i]);dis_list[i] = dis;dis_idx[i] = i;}memset(cylinders, 0, CYLINDER_MAX * sizeof(int));set_request(cylinders, request, req_num);printf("Head location: %d\n", head);//对dis_list从小到大进行排序,作为磁道请求序列for(int i = 0; i < req_num - 1; i++){for(int j = 0; j < req_num - i - 1; j++){if(dis_list[j] > dis_list[j+1]){int temp = dis_list[j];int temp_idx = dis_idx[j];dis_list[j] = dis_list[j+1];dis_idx[j] = dis_idx[j+1];dis_list[j+1] = temp;dis_idx[j+1] = temp_idx;} }}printf("Processing sequence: ");printf("%d ", head);for(int i = 0; i < req_num; i++){int req_id = request[dis_idx[i]];printf("%d ", req_id);cylinders[req_id]--;move_sum += abs(head - req_id);head = req_id;}printf("\nAverage total distance of head movement = %d\n", move_sum);printf("Average average response time = %f\n\n", (double)(move_sum/req_num));}void SCAN(int head, int *request, int *cylinders, int req_num, int dir){if(dir != 1 && dir != 0){printf("Direction Error\n");return;}printf("===============SCAN=============\n");int move_sum = 0;int pre_head = head;memset(cylinders, 0, CYLINDER_MAX * sizeof(int));set_request(cylinders, request, req_num);printf("Head location: %d\n", head);printf("Head moving sequence: ");printf("%d ", head);while(head >= 0 && head < CYLINDER_MAX){while(cylinders[head] > 0){printf("%d ", head);move_sum += abs(pre_head - head);pre_head = head;cylinders[head]--;}if(dir == 0) head--;else head++; }if(head == -1) head++;else if(head == CYLINDER_MAX) head--;// 移动到磁道尽头后, pre_head修改为head的位置,以便磁头换方向移动if(pre_head != head){printf("%d ", head);move_sum += abs(pre_head - head);pre_head = head;}if(dir == 1) dir = 0;else dir = 1;while(head >= 0 && head < CYLINDER_MAX){while(cylinders[head] > 0){printf("%d ", head);move_sum += abs(pre_head - head);pre_head = head;cylinders[head]--;}if(dir == 0) head--;else head++; }printf("\nAverage total distance of head movement = %d\n", move_sum);printf("Average average response time = %f\n\n", (double)(move_sum/req_num));}void C_LOOK(int head, int *request, int *cylinders, int req_num, int dir){if(dir != 1 && dir != 0){printf("Direction Error\n");return;}printf("===============C-LOOK=============\n");int move_sum = 0;int pre_head = head;int left = 0, right = 0;int flag = 0;memset(cylinders, 0, CYLINDER_MAX * sizeof(int));set_request(cylinders, request, req_num);for(int i = 0; i < CYLINDER_MAX; i++){if(cylinders[i] && !flag) {left = i;flag = 1;}if(flag && cylinders[i]){right = i;}}printf("Left Bound: %d, Right Bound: %d\n", left, right);printf("Head location: %d\n", head);printf("Head moving sequence: ");printf("%d ", head);while(head >= 0 && head < CYLINDER_MAX){//当磁头到达最远端的请求if(head == right && dir){ cylinders[head]--;break;}if(head == left && !dir) {cylinders[head]--;break;}while(cylinders[head] > 0){printf("%d ", head);move_sum += abs(pre_head - head);pre_head = head;cylinders[head]--;}//磁头按指定方向移动if(dir == 0) head--;else head++; }// 移动到磁道尽头后, pre_head修改为head的位置,以便磁头换方向移动if(pre_head != head){printf("%d ", head);move_sum += abs(pre_head - head);pre_head = head;}//直接移动到另一端最远的请求,过程中不处理请求if(dir == 1){head = left;cylinders[head]--;}else{head = right;cylinders[head]--;}printf("%d ", head);move_sum += abs(pre_head - head);pre_head = head;//磁头继续沿着指定方向移动while(head >= 0 && head < CYLINDER_MAX){while(cylinders[head] > 0){printf("%d ", head);move_sum += abs(pre_head - head);pre_head = head;cylinders[head]--;}if(dir == 0) head--;else head++; }printf("\nAverage total distance of head movement = %d\n", move_sum);printf("Average average response time = %f\n\n", (double)(move_sum/req_num));}int main(){int request[REQUEST_MAX];int cylinders[CYLINDER_MAX];int N, head, dir;printf("Please enter the number of requests for cylinders: ");scanf("%d", &N);printf("Please enter the queue with requests for cylinders: ");for(int i =0 ; i < N; i++){scanf("%d", &request[i]);}printf("Please input the head's position of cylinder: ");scanf("%d", &head);printf("Please enter the moving direction of the head (0: left, 1: right): ");scanf("%d", &dir);printf("\n");FCFS(head, request, cylinders, N);SSTF(head, request, cylinders, N);SCAN(head, request, cylinders, N, dir);C_LOOK(head, request, cylinders, N, dir);}

【操作系统】磁盘调度算法(FCFS、SSTF、SCAN 和 C-LOOK 调度策略)相关推荐

  1. 操作系统:磁盘调度算法FCFS算法(c语言)

    实验题目: 磁盘调度算法FCFS算法 实验内容: 磁盘访问序列和磁头起始位置(自己输入数据),采用SSTF磁盘调度算法,求平均寻道长度. 实验目的: 本课程设计的目的是通过磁盘调度算法设计一个磁盘调度 ...

  2. 操作系统 --- 磁盘调度算法

    文章目录 1.先来先服务调度算法(FCFS) 2.最短寻找时间调度算法(SSTF) 3.电梯调度算法(SCAN) 4.循环扫描算法(CSCAN) 5.磁盘调度算法练习题 多道环境下,进程并发运行随机提 ...

  3. 操作系统磁盘调度算法

    总返回目录 文章目录 缓冲管理 磁盘管理 N-step-SCAN算法 SSTF (离谁近就找谁算法) SCAN(坐电梯算法) 无特殊说明本片scan和c-scan默认为LOOK和C-look算法 缓冲 ...

  4. 操作系统 磁盘调度---扫描(SCAN)算法 (电梯调度算法)(C++实现 操作系统实验)

    思路: 不仅考虑到欲访问的磁道与当前磁道间的距离,更优先考虑的是磁头当前的移动方向,当磁头正在自里向外移动时,SCAN算法所考虑的下一个访问对象应是该磁头自里向外方向上距离最近的那个,直至扫描完最外面 ...

  5. 操作系统磁盘调度算法相关习题

    一.[问题描述] 假定磁盘有200个柱面,编号0~199,当前存取臂的位置在143号柱面上,并刚刚完成了125号柱面的服务请求,如果请求队列的先后顺序是:86,147,91,177,94,150,10 ...

  6. 操作系统作业调度算法c语言,操作系统课程设计报告电梯调度算法c语言实现.doc...

    操作系统课程设计报告电梯调度算法c语言实现 操作系统课程设计报告电梯调度算法c语言实现 :调度 算法 电梯 课程设计 操作系统 操作系统课程设计报告 模拟操作系统课程设计 写一个简单的操作系统 篇一: ...

  7. 磁盘调度算法寻道问题

    常用的磁盘调度算法有四种: 先来先服务算法(FCFS) 最短寻道时间优先算法(SSTF) 扫描算法(SCAN) 循环扫描算法(CSCAN) 先来先服务算法(First Come First Servi ...

  8. 操作系统之文件管理:9、磁盘的结构与磁盘调度算法(先来先服务FCFS、最短寻找时间优先SSTF、扫描算法SCAN、循环扫描算法C-SCAN、LOOK调度算法、C-LOOK调度算法)

    9.磁盘的结构 磁盘结构 思维导图 磁盘.磁道.扇区.盘面.柱面 如何在磁盘中读/写数据? 磁盘的物理地址 一次磁盘读/写操作需要的时间 磁盘调度算法 1.先来先服务FCFS 2.最短寻找时间优先SS ...

  9. 磁盘调度 FCFS、SSTF、SCAN 算法c++实现(大学生专用)

    前言 大家放实验报告里面的时候,好歹要把变量名什么的改改吧...一模一样的给老师发现就不好了... 代码 #include <iostream> #include <algorith ...

最新文章

  1. python语音转文字源码_【python3】Python十行代码搞定文字转语音
  2. winform point数组带数值_带你学够浪:Go语言基础系列 - 8分钟学复合类型
  3. JSP简单练习-页面重定向
  4. Android strings.xml中定义字符串显示空格
  5. java.lang.NoClassDefFoundError: org/apache/commons/codec/DecoderException 的解决办法
  6. linux服务器时间乱码问题解决
  7. 安装Qemu-6.1.0
  8. python中while。。。。else的用法
  9. creo管道设计教程_Creo7.0设计探索在管道设计的应用
  10. 大一新生应该如何学习C语言,书上代码看不懂理解不了怎么办?
  11. NIOS II 烧写epcs总结
  12. ansys轴对称模型之二维模型
  13. 【Java从入门到精通】第九篇:##你会继承你父亲的遗产吗?##来看看Java中是如何继承的吧#
  14. 【Questasim】报错001 Failed to access library
  15. JavaWEB(applicationjavabean封装)
  16. “首月0保费”导流模式告终 知名互联网保险平台开始裁员
  17. java joda range,Java:joda time
  18. 如何学好编程(一):什么叫编程
  19. 中国筒式过滤器行业市场供需与战略研究报告
  20. 佛说四十二章经(高丽版大藏经本)

热门文章

  1. linux安装mysql压缩包
  2. HTTP请求头与响应头
  3. C语言函数大全--g开头的函数(上)
  4. 软件测试|Python操作Excel制作报表,不要太方便
  5. 熊猫烧香病毒vbs版本 仅供研究
  6. Leaflet与OpenLayer
  7. 如何将传统 Node.js 项目部署到 Serverless
  8. 解决树莓派Ubuntu Mate开启远程桌面xrdp灰屏问题
  9. python鸢尾花分类svm测试集_使用SVM对鸢尾花分类
  10. python from import找不到库_如何查找python代码中所有未使用到的from与import的类库...