1、操作系统实 验 报 告课程名称 操作系统实验实验项目名称 磁盘调度算法学号 班级 20120616姓名 专业计算机科学与技术学生所在学院计算机科学与技术学院指导教师 初妍实验室名称地点 21#428哈尔滨工程大学计算机科学与技术学院1第六讲 磁盘调度算法一、实验概述1. 实验名称磁盘调度算法2. 实验目的(1)通过学习 EOS 实现磁盘调度算法的机制,掌握磁盘调度算法执行的条件和时机; (2)观察 EOS 实现的 FCFS、SSTF 和 SCAN 磁盘调度算法,了解常用的磁盘调度算法; (3)编写 CSCAN 和 N-Step-SCAN 磁盘调度算法,加深对各种扫描算法的理解。3. 实验类型验
2、证性+设计性实验4. 实验内容(1)验证先来先服务(FCFS)磁盘调度算法; (2)验证最短寻道时间优先(SSTF)磁盘调度算法; (3)验证 SSTF 算法造成的线程 “饥饿”现象; (4)验证扫描(SCAN )磁盘调度算法; (5)改写 SCAN 算法。 二、实验环境在 OS Lab 实验环境的基础上,利用 EOS 操作系统,由汇编语言及 C 语言编写代码,对需要的项目进行生成、调试、查看和修改,并通过 EOS 应用程序使内核从源代码变为可以在虚拟机上使用。三、实验过程1. 设计思路和流程图(1)改写 SCAN 算法在已有 SCAN 算法源代码的基础上进行改写,要求不再使用双重循环,而是只
3、遍历一次请求队列中的请求,就可以选中下一个要处理的请求。算法流程图如下图所示。2图 3.1.1 SCAN 算法 IopDiskSchedule 函数流程图(2)编写循环扫描(CSCAN)磁盘调度算法在已经完成的 SCAN 算法源代码的基础上进行改写,不再使用全局变量ScanInside 确定磁头移动的方向,而是规定磁头只能从外向内移动。当磁头移动到最内的被访问磁道时,磁头立即移动到最外的被访问磁道,即将最大磁道号紧接着最小磁道号构成循环,进行扫描。算法流程图如下图所示。图 3.1.2 CSCAN 算法 IopDiskSchedule 函数流程图(3)编写 N-Step-SCAN 磁盘调度算法在
4、已经完成的 SCAN 算法源代码的基础上进行改写,将请求队列分成若干个长度为 N 的子队列,调度程序按照 FCFS 原则依次处理这些子队列,而每处理一个子队列时,又是按照 SCAN 算法。算法流程图如下图所示。3图 3.1.3 N-Step-SCAN 算法 IopDiskSchedule 函数流程图2. 算法实现(1)改写 SCAN 算法在一次遍历中,不再关心当前磁头移动的方向,而是同时找到两个方向上移动距离最短的线程所对应的请求,这样就不再需要遍历两次。 在计算出线程要访问的磁道与当前磁头所在磁道的偏移后,可以将偏移分为三种类型:偏移为 0,表示线程要访问的磁道与当前磁头所在磁道相同,此情况
5、应该优先被调度,可立即返回该线程对应的请求的指针;偏移大于 0,记录向内移动距离最短的线程对应的请求;偏移小于 0,记录向外移动距离最短的线程对应的请求。循环结束后,根据当前磁头移动的方向选择同方向移动距离最短的线程,如果在同方向上没有线程,就变换方向,选择反方向移动距离最短的线程。(2)编写循环扫描(CSCAN)磁盘调度算法由于规定了磁头只能从外向内移动,所以在每次遍历中,总是同时找到向内移动距离最短的线程和向外移动距离最长的线程。注意,与 SCAN 算法查找向外移动距离最短线程不同,这里查找向外移动距离最长的线程。在开始遍历前,可以将用来记录向外移动最长距离的变量赋值为 0。在计算出线程要
6、访问的磁道与当前磁头所在磁道的偏移后,同样可以将偏移分为三种类型:偏移4为 0,表示线程要访问的磁道与当前磁头所在磁道相同,此情况应优先被调度,可立即返回该线程对应的请求的指针;偏移大于 0,记录向内移动距离最短的线程对应的请求;偏移小于 0,记录向外移动距离最长的线程对应的请求。循环结束后,选择向内移动距离最短的线程,如果没有向内移动的线程,就选择向外移动距离最长的线程。(3)编写 N-Step-SCAN 磁盘调度算法在 block.c 文件中的第 360 行定义了一个宏 SUB_QUEUE_LENGTH,表示子队列的长度(即 N 值 )。目前这个宏定义的值为 6。在第 367 行定义了一个
7、全局变量 SubQueueRemainLength,表示第一个子队列剩余的长度,并初始化其值为 SUB_QUEUE_LENGTH。在执行 N-Step-SCAN 算法时,要以第一个子队列剩余的长度做为计数器,确保只遍历第一个子队列剩余的项。所以,结束遍历的条件就既包括第一个子队列结束,又包括整个队列结束(如果整个队列的长度小于第一个子队列剩余的长度)。注意,不要直接使用第一个子队列剩余的长度做为计数器,可以定义一个新的局部变量来做为计数器。按照 SCAN 算法从第一个子队列剩余的项中选择一个合适的请求。最后,需要将第一个子队列剩余长度减少 1(SubQueueRemainLength 减少 1
8、),如果第一个子队列剩余长度变为 0,说明第一个子队列处理完毕,需要将子队列剩余的长度重新变为 N(SubQueueRemainLength 重新赋值为 SUB_QUEUE_LENGTH),从而开始处理下一个子队列。 3. 需要解决的问题及解答(1)实验指导 P176-3.2 验证先来先服务(FCFS )磁盘调度算法,要求请给出在“输出”窗口中的结果。答:先来先服务(FCFS)磁盘调度算法在“输出”窗口中的结果如下图所示。5图 3.3.1(2)实验指导 P177-3.3 验证验证最短寻道时间优先( SSTF)磁盘调度算法,要求请给出在“输出”窗口中的结果。答:最短寻道时间优先(SSTF)磁盘调
9、度算法在“输出”窗口中的结果如下图所示。6图 3.3.2(3)实验指导 P178-3.4 验证 SSTF 算法造成的线程“饥饿”现象,要求请给出在“输出”窗口中的结果。答:SSTF 算法造成的线程“饥饿”现象在“输出”窗口中的结果如下图所示。7图 3.3.3(4)实验指导 P179-3.5 验证扫描(SCAN)磁盘调度算法,要求在非饥饿(即实验指导P176-3.2 节中的数据)和饥饿(即 实验指导P178-3.4 节中的数据)请给出在“输出”窗口中的结果,并且要求在每次输入两次“ds”命令(注意不要连续输入,要等第一次“ds”命令执行完,再输入第二次“ds”命令),分析结果为什么不同。 答:在
10、非饥饿情况下,“输出”窗口中的结果如下图所示。8图 3.3.4在饥饿情况下,“输出”窗口中的结果如下图所示。9图 3.3.5ScanInside 是一个全局变量,当第一次执行 “ds”命令时,调用IopDiskSchedule 函数,ScanInside 被修改了一次,再次执行“ds”命令时,ScanInside 不会被重置,因此输出的结果会不一样。(5)在执行 SCAN、N-Step-SCAN 磁盘调度算法时,如果在 EOS 控制台中多次输入“ds”命令,调度的顺序会发生变化,说明造成这种现象的原因(提示:注意这两种算法使用的全局变量)。尝试修改源代码,使这两种算法在多次执行时,都能确保调度
11、的顺序一致(提示:可以参考 io/block.c 文件中IopReceiveRequest 函数和 IopProcessNextRequest 函数判断磁盘调度算法开始工作和结束工作的方法)。 答:ScanInside 是一个全局变量,当第一次执行 “ds”命令时,调用IopDiskSchedule 函数,ScanInside 被修改了一次,再次执行“ds”命令时,10ScanInside 不会被重置,因此输出的结果会不一样。只需在 for 循环结束后添加如下代码,就能确保调度的顺序一致。图 3.3.6(6)尝试在 io/block.c 文件中定义一个全局的函数指针变量 DiskSchedul
12、eFunc,该函数指针初始指向实现了 FCFS 算法的 IopDiskSchedule 函数。修改 io/block.c 文件中的 IopProcessNextRequest 函数,在该函数中不再直接调用 IopDiskSchedule 函数,而是调用函数指针 DiskScheduleFunc 指向的磁盘调度算法函数;ke/sysproc.c 文件中的 ConsoleCmdDiskSchedule 函数中也不再直接调用 IopDiskSchedule 函数,也要修改为调用函数指针DiskScheduleFunc 指向的磁盘调度算法函数。最后,添加一个控制台命令“sstf”,该命令使函数指针 D
13、iskScheduleFunc 指向实现了 SSTF 算法的函数。这样,在 EOS 启动后默认会执行 FCFS 算法,执行控制台命令 “sstf”后,会执行 SSTF 算法。按照这种方式依次实现“fcfs ”、“scan”、“cscan”和“nstepscan”命令。说明这种在 EOS 运行时动态切换磁盘调度算法的好处。答:首先在 block.c 中定义一个全局的函数指针变量 DiskScheduleFunc。图 3.3.7修改 IopProcessNextRequest 函数和 ConsoleCmdDiskSchedule 函数,使其不再直接调用 IopDiskSchedule 函数而是调用
14、函数指针 DiskScheduleFunc 指向的磁盘调度算法函数。图 3.3.8调用函数前先声明。11图 3.3.9添加一个控制台命令“sstf”,该命令使函数指针 DiskScheduleFunc 指向实现了 SSTF 算法的函数。图 3.3.10验证结果如下图所示。图 3.3.1112图 3.3.12(7)分析已经实现的各种磁盘调度算法的优缺点,尝试实现更多其它的磁盘调度算法。 答:先来先服务算法是一种比较简单的磁盘调度算法,它根据进程请求访问磁盘的先后次序进行调度,此算法的优点是公平、简单,且每个进程的请求都能依次得到处理,不会出现某一进程的请求长期得不到满足的情况,在对磁盘的访问请求
15、比较多的情况下,致使平均寻道时间可能较长;最短寻道时间优先算法选择这样的进程,其要求访问的磁道与当前磁头所在的磁道距离最近,以使每次的寻道时间最短,该算法可以得到比较好的吞吐量,但却不能保证平均寻道时间最短,其缺点是在服务请求很多的情况下,对内外边缘磁道的请求将会无限期的被延迟;扫描算法不仅考虑到欲访问的磁道与当前磁道的距离,更优先考虑的是磁头的当前移动方向,此算法基本上克服了最短寻道时间优先算法的服务集中于中间磁道和响应时间变化比较大的缺点,而具有最短寻道时间优先算法的优点即吞吐量较大,平均响应时间较小,但由于是摆动式的扫描方法,两侧磁道被访问的频率仍低于中间磁道;循环扫描算法是对扫描算法的
16、改进,如果对磁道的访问请求是均匀分布的,当磁头到达磁盘的一端,并反向运动时落在磁头之后的访问请求相对较少;N-Step-SCAN 算法是扫描算法和先来先服务算法的一个综合算法,将请求队列分成若干个长度为 N 的子队列,13调度程序按照 FCFS 原则依次处理这些子队列,而每处理一个子队列时,又是按照 SCAN 算法,所以它是一种性能比较平均的算法。(6)EOS 在块设备层实现了磁盘调度算法后,由于请求队列中的请求一定是被逐个处理的,所以并发的多个线程已经可以互斥的访问磁盘上的数据,那为什么在 IopReadWriteSector 函数中还要使用磁盘设备的互斥信号量进行互斥呢?(提示:如果一个线
17、程只是要获取磁盘设备的状态而不是要访问磁盘上的数据,是否需要对该线程进行磁盘调度?该线程是否要与其它并发访问磁盘设备的线程进行互斥?)答:如果一个线程只是要获取磁盘设备的状态而不是要访问磁盘上的数据,那这个线程是不需要进行磁盘调度的,所以不会进入请求队列,但该线程同样需要与其它并发访问磁盘设备的线程进行互斥,这时就需要使用磁盘设备的互斥信号量进行互斥。4. 源程序并附上注释(1)改写 SCAN 算法BOOL ScanInside = TRUE;PREQUESTIopDiskSchedule(VOID)PLIST_ENTRY pListEntry;PREQUEST pRequest;PREQUE
18、ST INpNextRequest = NULL;PREQUEST OUTpNextRequest = NULL;LONG Offset;ULONG InsideShortestDistance = 0xFFFFFFFF;ULONG OutsideShortestDistance = 0xFFFFFFFF;PREQUEST pNextRequest = NULL;/ 需要遍历请求队列一次或两次for (pListEntry = RequestListHead.Next; / 请求队列中的第一个请求是链表头指/向的下一个请求。pListEntry != / 遍历到请求队列头14时结束循环。pLi
19、stEntry = pListEntry-Next) / 根据链表项获得请求的指针pRequest = CONTAINING_RECORD(pListEntry, REQUEST, ListEntry);/ 计算请求对应的线程所访问的磁道与当前磁头所在磁道的偏移(方向由正负表示)Offset = pRequest-Cylinder - CurrentCylinder;if (0 = Offset) / 如果线程要访问的磁道与当前磁头所在磁道相同,可立即返回。pNextRequest = pRequest;goto RETURN; else if ( Offset 0 16/ 计算请求对应的线程
20、所访问的磁道与当前磁头所在磁道的偏移(方向由正负表示)Offset = pRequest-Cylinder - CurrentCylinder;if (0 = Offset) / 如果线程要访问的磁道与当前磁头所在磁道相同,可立即返回。pNextRequest = pRequest;goto RETURN; else if ( Offset 0 OUTpNextRequest = pRequest;/需要向内移动的线程是否存在if( INpNextRequest )/存在则返回向内移动的请求return INpNextRequest;else/否则返回向外移动的请求return OUTpNex
21、tRequest;RETURN:return pNextRequest;(3)编写 N-Step-SCAN 磁盘调度算法/ N-Step-SCAN 磁盘调度算法使用的子队列长度N#define SUB_QUEUE_LENGTH 6/ 记录N-Step-SCAN 磁盘调度算法第一个子队列剩余的长度。/ 子队列初始长度为N,每执行一次磁盘调度算法会从子队列中移除一个请求,子队列17/ 长度就要减少1,待长度变为0 时,再将长度重新变为 N,开始处理下一个子队列。ULONG SubQueueRemainLength = SUB_QUEUE_LENGTH;/ 扫描算法中磁头移动的方向。操作系统启动时初
22、始化为磁头向内移动。/ TRUE,磁头向内移动,磁道号增加。/ FALSE,磁头向外移动,磁道号减少。BOOL ScanInside = TRUE;PREQUESTIopDiskSchedule(VOID)PLIST_ENTRY pListEntry;PREQUEST pRequest;PREQUEST INpNextRequest = NULL;PREQUEST OUTpNextRequest = NULL;LONG Offset;ULONG InsideShortestDistance = 0xFFFFFFFF;ULONG OutsideShortestDistance = 0xFFFFF
23、FFF;PREQUEST pNextRequest = NULL;ULONG counter;/ 需要遍历请求队列一次或两次/计数器记录一个子队列剩余的长度counter = SubQueueRemainLength;/没调度一次子队列剩余的长度减SubQueueRemainLength-;/如果子队列剩余的长度为,则重置为子队列原长度if(SubQueueRemainLength = 0)SubQueueRemainLength = SUB_QUEUE_LENGTH;for (pListEntry = RequestListHead.Next; / 请求队列中的第一个请求是链表头指/向的下一
24、个请求。pListEntry != / 遍历到请求队列头时结/束循环或子队列结束。pListEntry = pListEntry-Next) / 根据链表项获得请求的指针pRequest = CONTAINING_RECORD(pListEntry, REQUEST, ListEntry);/ 计算请求对应的线程所访问的磁道与当前磁头所在磁道的偏移(方向由正负表示)Offset = pRequest-Cylinder - CurrentCylinder;if (0 = Offset) 18/ 如果线程要访问的磁道与当前磁头所在磁道相同,可立即返回。pNextRequest = pRequest
25、;return pNextRequest; else if ( Offset 0 INpNextRequest = pRequest; else if ( Offset 0 OUTpNextRequest = pRequest;counter-;if( ScanInside )if(INpNextRequest)return INpNextRequest;elseScanInside = !ScanInside;return OUTpNextRequest;elseif(OUTpNextRequest)return OUTpNextRequest;elseScanInside = !ScanI
26、nside;return INpNextRequest;195. 程序运行时的初值和运行结果(1)验证先来先服务(FCFS)磁盘调度算法新建一个 EOS Kernel 项目,双击 ke 文件夹中的 sysproc.c 文件,阅读函数ConsoleCmdDiskSchedule,目前该函数使磁头初始停留在磁道 10,其它被阻塞的线程依次访问磁道 8、21、9、78、0、41、10、67、12、10。按 F5 调试项目,待 EOS 启动完毕,在 EOS 控制台中输入命令“ds”后按回车。控制台和输出窗口显示内容如下图所示。图 3.5.220图 3.5.3对比 EOS 控制台和“输出”窗口中的内容,
27、可以发现 FCFS 算法是根据线程访问磁盘的先后顺序进行调度的。(2)验证最短寻道时间优先(SSTF)磁盘调度算法使用 sstf.c 文件中 IopDiskSchedule 函数的函数体,替换 block.c 文件中 IopDiskSchedule 函数的函数体。按 F7 生成项目,然后按 F5 启动调试。待 EOS 启动完毕,在 EOS 控制台中输入命令“ds” 后按回车。输出窗口输出结果如下图所示。21图 3.5.4(3)验证 SSTF 算法造成的线程 “饥饿”现象修改 sysproc.c 文件 ConsoleCmdDiskSchedule 函数中的源代码,仍然使磁头初始停留在磁道 10,
28、而让其它线程依次访问磁道78、21、9、8、11、41、10、67、12、10。按 F7 生成项目,然后按 F5 启动调试。 待 EOS 启动完毕,在 EOS 控制22台中输入命令“ds”后按回车。输出窗口输出结果如下图所示。图 3.5.5(4)验证扫描(SCAN )磁盘调度算法 使用 scan.c 文件中 IopDiskSchedule 函数的函数体,替换 block.c 文件中 IopDiskSchedule 函数的函数体。按 F7 生成项目,然后按 F5 启动调试。 待 EOS 启动完毕,在 EOS 控制台中输入命令“ds” 后按回车。输出窗口输出内容如下图所示。23图 3.5.6再次输
29、入“ds”命令,输出窗口输出内容如下图所示。图 3.5.7(5)改写 SCAN 算法修改完代码后,按 F7 生成项目,然后按 F5 启动调试。待 EOS 启动完毕,在 EOS 控制台中输入命令“ds”后按回车。输出窗口输出内容如下图所示。24图 3.5.8调试结果与预期一致,说明算法改写正确。图 3.5.9(6)编写循环扫描(CSCAN)磁盘调度算法修改完代码后,按 F7 生成项目,然后按 F5 启动调试。待 EOS 启动完毕,在 EOS 控制台中输入命令“ds”后按 回车。输出窗口输出内容如下图所示。25图 3.6.10调试结果与预期一致,说明算法改写正确图 3.5.11(7)验证 SSTF
30、、SCAN 及 CSCAN 算法中的“磁臂粘着”现象修改 sysproc.c 文件26ConsoleCmdDiskSchedule 函数中的源代码,仍然使磁头初始停留在磁道 10,而让其它线程依次访问磁道 78、10、10、10、10、10、10、10、10、10。 分别使用 SSTF、 SCAN 和 CSCAN 算法调度这组数据。输出窗口输出内容如下图所示。SSTF“磁臂粘着 ”现象:图 3.5.12SCAN“磁臂粘着 ”现象:27图 3.5.13CSCAN“磁臂粘着”现象:28图 3.5.14(8)编写 N-Step-SCAN 磁盘调度算法 修改完代码后,按 F7 生成项目,然后按 F5 启动调试。待 EOS 启动完毕,在 EOS 控制台中输入命令“ds”后按回车。输出窗口输出内容如下图所示。29图 3.5.15调试结果与预期一致,说明算法改写正确。图 3.5.16SUB_QUEUE_LENGTH=100 时