磁盘调度算法
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
在临界区 中完成对 临界资源 (块设 备)的访 问
是
读取数据?
否
从缓存中读取 指定的字节
修改缓存中 指定的字节 调用设备驱动程序的Write功能 函数,将缓存写回扇区 线程退出临界区时,会将设 备互斥信号量等待队列中的 第一个线程唤醒,使之进入 临界区。
释放设备互斥信号量 (退出临界区) IopReadWriteSector 函数结束
PsWaitForMutex(&DiskScheduleMutex, INFINITE);
if (IsDeviceBusy) { PsResetEvent(&pRequest->Event); } else { IsDeviceBusy = TRUE; } ListInsertTail(&RequestListHead, &pRequest->ListEntry); PsReleaseMutex(&DiskScheduleMutex); PsWaitForEvent(&pRequest->Event, INFINITE); return pRequest; }
执行的条件、执行的时机、操作的对象
条件:多个线程并发访问同一个磁盘设备 才会触发磁盘调度算法。单个线程访问磁 盘不会触发磁盘调度算法。 时机:将阻塞线程唤醒时执行调度,而不 是将线程阻塞时执行调度。 对象:由于并发访问同一个磁盘设备而被 阻塞的多个线程。
EOS中实现的磁盘调度算法
目前EOS只管理了一个块设备——软盘驱动器, 为了尽量简单,EOS只考虑对这个唯一的块设备 进行磁盘调度。 为每个访问磁盘的线程创建一个对应的请求,并 将这些请求放入一个请求队列中。 在块设备读写函数IopReadWriteSector中依次处 理请求队列中的请求,各个请求被处理的顺序由 磁盘调度算法决定。 在函数IopDiskSchedule中实现各种磁盘调度算法。 控制台命令“ds”专门用来测试磁盘调度算法。
if (ListIsEmpty(&RequestListHead)) { IsDeviceBusy = FALSE; } else { pNextRequest = IopDiskSchedule(); PsSetEvent(&pNextRequest->Event); }
PsReleaseMutex(&DiskScheduleMutex); } // 退出临界区
实
验
磁盘调度算法
实验目的
通过学习EOS实现磁盘调度算法的机制, 掌握磁盘调度算法执行的条件和时机。 观察EOS实现的FCFS、SSTF和SCAN磁 盘调度算法,了解常用的磁盘调度算法。 编写CSCAN和N-Step-SCAN磁盘调度算法, 加深对各种扫描算法的理解。
多线程并发访问软盘
从用户的角度看( 宏观上),三个线 程是在同时访问软 盘上的数据。 从线程的角度看(微 观上),三个线程是 在交替的访问软盘上 的单个扇区。 从软盘驱动器的角度看, 它甚至根本不知道线程的 存在,只是根据请求来访 问软盘上的各个扇区。
IopProcessNextRequest(pCurrentRequest);
}
IopReceiveRequest函数
PREQUEST IopReceiveRequest( IN ULONG SectorNumber ) { PREQUEST pRequest; pRequest = (PREQUEST)MmAllocateSystemPool( sizeof(REQUEST) ); pRequest->Cylinder = SectorNumber / 18 / 2; PsInitializeEvent(&pRequest->Event, TRUE, TRUE);
请求B
访问磁道21 链表项 事件有效
请求C
访问磁道9 链表项 事件无效 阻塞 链表头
访问磁道21 链表项 事件无效 阻塞
忙
线程 B (4)
线程 C
忙
访问
线程 B (5)
线程 C
空闲
(6)
专门用来测试磁盘调度算法的控制台命令“ds”
该控制台命令是在ke/sysproc.c文件中的 ConsoleCmdDiskSchedule函数内实现的。在该 函数执行的过程中,首先让当前线程访问一次磁 盘上的某个磁道,从而设置磁头的初始位置,然 后将磁盘设备的状态设置为忙,并创建多个访问 不同磁道的线程。由于磁盘设备忙,这些线程的 请求都会被放入请求队列中,直到被磁盘调度算 法选中后才会被处理。最后触发磁盘调度算法, 按照调度策略依次处理请求队列中的所有请求。 优点:
请求A
链表头 链表头 访问磁道8 链表项 事件有效 链表头
请求A
访问磁道8 链表项 事件有效
请求B
访问磁道21 链表项 事件无效 阻塞
请求C
访问磁道9 链表项 事件无效 阻塞
空闲
忙
访问
线程 A
忙
访问
线程 A (3)
线程 B
线程 C
(1) 请求B
链表头
(2) 请求C
访问磁道9 链表项 事件无效 阻塞 链表头
读105扇区
磁盘调度算法在EOS中的位置
ReadFile()
用户态 核心态 应用程序 应用程序 应用程序
……
用户态 核心态
FatReadFile()
FAT12 文件系统
FAT32 文件系统
ISO-9660 文件系统
……
可以在块设备 层中加入磁盘 调度算法和读 写缓冲区管理 功能。
IopReadWriteSector()
实现了FCFS算法的IopDiskSchedule函数
PREQUEST IopDiskSchedule( VOID ) { PLIST_ENTRY pListEntry; PREQUEST pNextRequest;
pListEntry = RequestListHead.Next; pNextRequest = CONTAINING_RECORD(pListEntry, REQUEST, ListEntry); return pNextRequest;
}
CBA
IopReceiveRequest 函数开始
创建一个请求 (分配内存) 初始化新创建的请求 (记录线程访问的磁道号) 等待磁盘调度互斥信号量 (进入临界区)
IopReadWriteSector 函数开始
IopProcessNextRequest 函数开始
等待磁盘调度互斥信号量 (进入临界区) 记录当前磁头 所在的磁道号 将已处理完毕的请求从 请求队列中移除 销毁已处理完毕的请求 (释放内存)
软盘驱动器 及驱动程序
块设备
FloppyRead()
硬盘驱动器 及驱动程序
光盘驱动器 及驱动程序
……
(a)
(b)
磁盘调度算法 执行的条件、执行的时机、操作的对象
当多个线程并发访问磁盘时,只能有一个线 程访问磁盘(独占磁盘),而其它的线程会被阻 塞,待独占磁盘的线程结束访问操作后,才能唤 醒一个阻塞的线程,令其继续独占访问磁盘。 这里提到的唤醒一个阻塞的线程的过程,就 是磁盘调度算法工作的过程。可能会有多个线程 由于并发访问磁盘而被阻塞,磁盘调度算法就是 根据不同的策略,从中选择一个合适的线程来唤 醒。 准确的说,磁盘调度算法操作的对象是—— 由于并发访问同一个磁盘设备而被阻塞的多个线 程。
文件io/block.c中的磁盘调度算法函数 IopDiskSchedule
PREQUEST IopDiskSchedule( VOID )
可以实现多种磁盘调度算法,包括FCFS、SSTF、SCAN、 CSCAN、N-Step-SCAN等,目前仅实现了最简单的FCFS 算法。 当前磁头所在的磁道保存在全局变量 CurrentCylinder 中。 请求队列中各个请求的 Cylinder 域保存了对应线程要访问 的磁道号。 注意,该函数只是从请求队列中选择下一个要被处理的请 求,而不需要将选中的请求从请求队列中移除,也不需要 将请求对应的线程唤醒。
// 进入临界区
// 退出临界区
IopProcessNextRequest函数
VOID IopProcessNextRequest( IN PREQUEST pCurrentRequest ) { PREQUEST pNextRequest; PsWaitForMutex(&DiskScheduleMutex, INFINITE); CurrentCylinder = pCurrentRequest->Cylinder; ListRemoveEntry(&pCurrentRequest->ListEntry); MmFreeSystemPool(pCurrentRequest); // 进入临界区
等待设备互斥信号量 (进入临界区) 调用设备驱动程序的Read功能 函数,将整个扇区读入缓存
是
读取数据?
否
是
磁盘设备忙?
否 从缓存中读取 指定的字节 修改缓存中 指定的字节 调用设备驱动程序的Write功能 函数,将缓存写回扇区
设置请求中 的事件无效
设置磁盘 设备忙
是请求队列 变为空?否将请求插入到 请求队列的末尾 释放磁盘调度互斥信号量 (退出临界区) 当前线程等待其对应请 求中的事件 释放设备互斥信号量 (退出临界区)
用户
线程1 访问文件A
读89扇区
阻塞
线程2 访问文件B
阻塞
线程3 访问文件C
阻塞
软盘驱动器
读89扇区 写100扇区 读103扇区 读90扇区 写101扇区 写104扇区 读91扇区 写106扇区 读105扇区
写100扇区
阻塞
读103扇区
阻塞
读90扇区
阻塞
写101扇区
阻塞
写104扇区
阻塞
读91扇区
写106扇区
磁盘调度算法使用的重要结构体和全局变量
用于创建请求的结构体在io/iop.h文件中定义如下: typedef struct _REQUEST { ULONG Cylinder; LIST_ENTRY ListEntry; EVENT Event; }REQUEST, *PREQUEST; 在io/block.c文件中定义了一组全局变量 : MUTEX DiskScheduleMutex; BOOL IsDeviceBusy; ULONG CurrentCylinder; LIST_ENTRY RequestListHead;
方便指定线程的数量、各个线程要访问的 磁道号以及线程被阻塞的顺序。 与磁盘上使用的文件系统无关。
ke/sysproc.c文件中的ConsoleCmdDiskSchedule函数
PRIVATE VOID ConsoleCmdDiskSchedule( IN HANDLE StdHandle ) { PREQUEST pNextRequest; extern BOOL IsDeviceBusy; ULONG StartCylinder = 10; AccessCylinderThread((PVOID)StartCylinder); fprintf(StdHandle, "Start Cylinder: %d\n", StartCylinder); IsDeviceBusy = TRUE; NewThreadAccessCylinder(StdHandle, 8); NewThreadAccessCylinder(StdHandle, 21); ……
在函数IopReadWriteSector中调用 磁盘调度算法相关函数
STATUS IopReadWriteSector(……) { PREQUEST pCurrentRequest; pCurrentRequest = IopReceiveRequest(SectorNumber);
……// 处理请求。与原有操作完全相同。
还未实现磁盘调度算法时IopReadWriteSector函数的流程图
IopReadWriteSector 函数开始 等待设备互斥信号量 (进入临界区) 调用设备驱动程序的Read功能 函数,将整个扇区读入缓存 多线程并发访问块设备时, 只能有一个线程进入临界 区,其它线程按照先后顺序 阻塞在设备互斥信号量的等 待队列中。阻塞的线程被唤 醒后从这里继续向下执行。
磁盘设备退 出忙状态
磁盘调度算 法选择请求 设置请求中 的事件有效
IopReadWriteSector 函数结束
释放磁盘调度互斥信号量 (退出临界区)
IopReceiveRequest 函数结束
IopProcessNextRequest 函数结束
(a)
(b)
(c)
并发访问软盘的多个线程,在请求队列中阻 塞与唤醒的过程