操作系统实验三-驱动调度(一)

简介: 操作系统实验三-驱动调度

一、实验内容

 模拟电梯调度算法,实现对磁盘的驱动调度。

二、实验目的

 磁盘是一种高速、大容量、旋转型、可直接存取的存储设备。它作为计算机系统的辅助存储器,担负着繁重的输入输出任务。在多道程序设计系统中,往往同时会有若干个要求访问磁盘的输入输出请求等待处理。系统可采用一种策略,尽可能按最佳次序执行要求访问磁盘的诸输入输出请求。这就叫驱动调度,使用的算法称为驱动调度算法。驱动调度能降低为若干个输入输出请求服务所需的总时间,从而提高系统效率。本实验要求学生模拟设计一个驱动调度程序,观察驱动调度程序的动态运行过程。通过实验使学生理解和掌握驱动调度的职能。

三、实验题目

 模拟电梯调度算法,对磁盘进行移臂和旋转调度。

 (1)磁盘是可供多个进程共享的存储设备,但一个磁盘每时刻只能为一个进程服务。当有进程在访问某个磁盘时,其他想访问该磁盘的进程必须等待,直到磁盘一次工作结束。当有多个进程提出输入输出要求而处于等待状态时,可用电梯调度算法从若干个等待访向者中选择一个进程,让它访问磁盘。选择访问者的工作由“驱动调度"进程来完成。

 由于磁盘与处理器是可以并行工作的,所以当磁盘在作为一个进程服务时,占有处理器的另一进程可以提出使用磁盘的要求。也就是说,系统能动态地接收新的输入输出请求。为了模拟这种情况,在本实验中设置了一个“接收请求”进程。

 “驱动调度”进程和“接收请求”进程能否占有处理器运行,取决于磁盘的结束中断信号和处理器调度策略。在实验中可用随机数来模拟确定这两个进程的运行顺序,以代替中断处理和处理器调度选择的过程。因而,程序的结构可参考图。

进程名 柱面号 磁道号 物理记录号

 假定某个磁盘组共有200个柱面,由外向里顺序编号(0-199),每个柱面上有20个磁道,编号为0-19,每个磁道分成8个物理记录,编号0-7。进程访问磁盘的物理地址可以用键盘输入的方法模拟得到。图2是“接收请求”进程的模拟算法。

 在实际的系统中必须把等待访问磁盘的进程排入等待队列,由于本实验模拟驱动调度,为简单起见,在实验中可免去队列管理部分,故设计程序时可不考虑“进程排入等待队列”的工作。

  (3)“驱动调度”进程的功能是查“请求I/O”表,当有等待访问磁盘的进程时,按电梯调度算法从中选择一个等待访问者,按该进程指定的磁盘物理地址启动磁盘为其服务。

  对移动臂磁盘来说,驱动调度分移臂调度和旋转调度。电梯调度算法的调度策略是与移动臂的移动方向和移动臂的当前位置有关的,所以每次启动磁盘时都应登记移动臂方向和当前位置。电梯调度算法是一种简单而实用的驱动调度方法,这种调度策略总是优先选择与当前柱面号相同的访问请求,从这些请求中再选择一个能使旋转距离最短的等待访问者。如果没有与当前柱面号相同的访问请求,则根据移臂方向来选择,每次总是沿臂移动方向选择一个与当前柱面号最近的访问请求,若沿这个方向没有访问请求时,就改变臂的移动方向。这种调度策略能使移动臂的移动频率极小,从而提高系统效率。用电梯调度算法实现驱动调度的模拟算法如图。(实验指导书上的流程图有误!!!)

  (4)图1中的初始化工作包括:初始化“请求1/O”表、置当前移臂方向为向里移,置当前位置为0号柱面、0号物理记录。程序运行前可假定“请求I/O"表中已经有若干个进程等待访问磁盘。

  在模拟实验中,当选中一个进程可以访问磁盘时,并不实际地启动磁盘,而用显示:“请求I/0”表、当前移臂方向、当前柱面号、物理记录号来代替图3

中的“启动磁盘”这项工作。

四、实验报告

(1)实验题目

见上文

(2)程序中使用的数据结构及其说明

数据结构:

 请求I/O表:需要说明的是,请求I/O表的数据项与实验指导书略有不同实验指导书可能有误!!!),每个数据项的四个属性分别为进程id、柱面号、盘面号、扇区号。

struct process {
  int id;
  int cylinder;
  int track;
  int sector;
};

 请求I/O表用到的物理结构不是数组,而是采取了可变长数组vector。因为要频繁地查表并得知请求I/O表的进程数量,所以利用vector的size()属性可以方便地得知当前进程数量而无需我们手动维护。

vector<process> iorequests;

 因为是模拟程序,所以我们可以直接将当前移臂方向、当前柱面号、当前扇区号都直接设置为全局变量。

bool direction;//0 up,1down 
int curCylinder;
int curSector;

 在模拟调度中,需要记录是否有与当前柱面号相同的访问者。同样的,这些访问者也可以用一个vector暂存。

vector<int> sameCylinderpos;//当前柱面号相同访问者

(3)打印一份源程序并附上注释

1.程序说明

 main函数执行两个函数,分别为初始化与模拟cpu运行。

int main() {
  init();
  cpuwork();
}

 初始化时,将当前移臂方向为向里移,当前柱面号为0号柱面,当前扇区号为0号扇区。

void init() {
  direction = 0;
  curCylinder = 0;
  curSector = 0;
  direction = 0;
}

 处理机工作,与图1是一致的。生成随机数,并根据随机数决定当前在驱动调度或接受请求。

void cpuwork() {
  srand(time(NULL));
  while (1) {
    cout << "1. Drive scheduling 2.Accept Requests";
    double opnum= rand() / double(RAND_MAX);
    if (opnum > 0.5) 
      driveScheduling();
    else
      acceptRequest();
    cout << "Continue?Y/N";
    char op;
    cin >> op;
    if (op == 'Y');
    else
      break;
  }
}

 在接受请求时,简化了进程进入等待队列。但是仍然会输入与登记I/O请求表。

void acceptRequest() {
  cout << "\nAccepting requests!";
  cout << "\ninput request num:";
  int n;
  cin >> n;
  if (n == 0) {//不发送请求
    cout << "No requests!";
    return;
  }
  else while(n--) {
    cout << "input process id,cylinder,track,sector";
    int id, cylinder, track, sector;
    cin >> id >> cylinder >> track >> sector;
    process newp(id, cylinder, track, sector);
    iorequests.push_back(newp);
  }
}

 在电梯模拟调度算法中,为了减少对I/O请求表的遍历次数,本程序采用的流程与流程图略有区别。先遍历数组,利用vector sameCylinderpos记录与当前柱面号相同的访问者。若这个可变长数组长度大于0,则说明有与当前柱面号相同的访问者。在遍历数组过程中,同时利用标记与位置值判断有无并找到大于当前柱面号的请求中的最小者和小于当前柱面号请求的最大者。

 需要着重说明的是流程图中有一个步骤是“选择能使旋转距离最短的访问者”。由于磁盘只能一个方向旋转,所以在这一步骤中需要进行一定的数学处理。记请求的扇区号为y,磁盘当前扇区号为x。磁盘的某一个柱面的一个盘面上8个扇区。可以利用简单的数学知识,统一地用一个式子对磁盘旋转记录进行表示:(x+8-y)%8。例如,磁盘当前在4号扇区,有一个请求在7号扇区,则(7+8-4)%8=3,磁盘要转动3个单位。还有个请求在1号扇区,则(1+8-4)%8=5,磁盘要转动五个单位。

 若没有与当前柱面号相同的访问者,则剩余过程与实验指导书类似,但是对请求的判断与选择如上文所述,都是在第一次对数组的遍历时处理好。

void driveScheduling() {//驱动调度
  if (iorequests.empty()) //当前有无等待访问者
    return;
  else {
    bool sameCylinder = 0;//有无与当前柱面号相同访问者
    bool greaterCylinder = 0;//有无大于当前柱面号访问者
    bool lesserCylinder = 0;//有无小于当前柱面号访问者
    sameCylinderpos.clear();
    int mingtCylinderpos=-1;//大于当前柱面号的最小者
    int maxltCylinderpos=-1;//小于当前柱面号的最大者
    int iorequestPos=0;//位置
    for (int i = 0; i < iorequests.size(); i++) {//判断有无与当前柱面号相同访问者,比当前大的请求、比当前小的请求
      if (iorequests[i].cylinder == curCylinder) {
        sameCylinder = 1;
        sameCylinderpos.push_back(i);//与当前柱面号相同的访问者,放入可变长数组中暂存
      }
      if (iorequests[i].cylinder > curCylinder) {//从大于当前柱面号请求中选一个最小者
        greaterCylinder = 1;
        if (mingtCylinderpos == -1)
          mingtCylinderpos = i;
        if (iorequests[i].cylinder < iorequests[mingtCylinderpos].cylinder) 
          mingtCylinderpos = i;
      }
      if (iorequests[i].cylinder < curCylinder) {//从小于当前柱面号请求中选一个最大者
        lesserCylinder = 1;
        if (maxltCylinderpos == -1)
          maxltCylinderpos = i;
        if (iorequests[i].cylinder > iorequests[maxltCylinderpos].cylinder)
          maxltCylinderpos = i;
      }
    }
    if (sameCylinder == 1) {//选使得旋转距离最短的访问者
      int rotateDist = 20;
      iorequestPos = sameCylinderpos[0];
      for (int i=0;i<sameCylinderpos.size();i++) {
        int pos = sameCylinderpos[i];
        int& x = iorequests[pos].sector;
        int& y = curSector;
        int dist = ((x+8-y)%8);
        if (dist < rotateDist) {//选择能使旋转距离最短的访问者
          rotateDist = dist;
          iorequestPos = pos;
        }
      }
    }
    else {
      if (direction == 0) {
        if (greaterCylinder)
          iorequestPos = mingtCylinderpos;
        else {
          direction = 1;//置移臂方向
          iorequestPos = maxltCylinderpos;
        }
      }
      else {
        if (lesserCylinder)
          iorequestPos = maxltCylinderpos;
        else {
          direction = 0;//置移臂方向为往里
          iorequestPos = mingtCylinderpos;
        }
      }
    }
    curCylinder = iorequests[iorequestPos].cylinder;
    curSector = iorequests[iorequestPos].sector;
    iorequests.erase(iorequests.begin() + iorequestPos);
  }
}


目录
相关文章
|
3月前
|
算法 调度 UED
探索操作系统的心脏:调度算法的奥秘与影响
【10月更文挑战第9天】 本文深入探讨了操作系统中至关重要的组件——调度算法,它如同人体的心脏,维持着系统资源的有序流动和任务的高效执行。我们将揭开调度算法的神秘面纱,从基本概念到实际应用,全面剖析其在操作系统中的核心地位,以及如何通过优化调度算法来提升系统性能。
|
2月前
|
算法
数据结构实验之操作系统打印机管理器问题
本实验旨在通过实现操作系统中的打印机管理器问题,掌握队列的基本操作如入队、出队等,利用队列的先进先出特性解决先申请先打印的问题。实验包括队列的初始化、入队、出队、打印队列内容等功能,并通过菜单式界面进行交互。实验结果显示基本功能可正常执行,但在连续操作时存在执行失败的情况,需进一步优化。
51 4
|
2月前
|
算法 调度 UED
深入理解操作系统:进程调度与优先级队列
【10月更文挑战第31天】在计算机科学的广阔天地中,操作系统扮演着枢纽的角色,它不仅管理着硬件资源,还为应用程序提供了运行的环境。本文将深入浅出地探讨操作系统的核心概念之一——进程调度,以及如何通过优先级队列来优化资源分配。我们将从基础理论出发,逐步过渡到实际应用,最终以代码示例巩固知识点,旨在为读者揭开操作系统高效管理的神秘面纱。
|
1月前
|
存储 算法 调度
深入理解操作系统:进程调度的奥秘
在数字世界的心脏跳动着的是操作系统,它如同一个无形的指挥官,协调着每一个程序和进程。本文将揭开操作系统中进程调度的神秘面纱,带你领略时间片轮转、优先级调度等策略背后的智慧。从理论到实践,我们将一起探索如何通过代码示例来模拟简单的进程调度,从而更深刻地理解这一核心机制。准备好跟随我的步伐,一起走进操作系统的世界吧!
|
2月前
|
消息中间件 算法 调度
深入理解操作系统:进程管理与调度
操作系统是计算机系统的核心,负责管理和控制硬件资源、提供用户接口以及执行程序。其中,进程管理是操作系统的重要组成部分,它涉及到进程的创建、调度、同步和通信等方面。本文将深入探讨进程管理的基本概念、进程调度算法以及进程间的同步和通信机制。通过本文的学习,读者将能够更好地理解操作系统的工作原理,并掌握进程管理的基本技能。
60 11
|
2月前
|
算法 调度 UED
深入理解操作系统:进程管理与调度策略
操作系统作为计算机系统的核心,其进程管理和调度策略对于系统性能和用户体验至关重要。本文将通过直观的代码示例和浅显易懂的语言,带领读者了解操作系统如何有效管理进程以及常见的进程调度算法。我们将从进程的基本概念出发,逐步深入到进程状态、进程控制块(PCB)的作用,最后探讨不同的调度算法及其对系统性能的影响。无论您是初学者还是有一定基础的开发者,都能从中获得有价值的信息。
|
2月前
|
负载均衡 算法 调度
深入理解操作系统:进程管理与调度
在数字世界的心脏,操作系统扮演着至关重要的角色。它如同一位精明的指挥家,协调着硬件资源和软件需求之间的和谐乐章。本文将带你走进操作系统的核心,探索进程管理的艺术和调度策略的智慧。你将了解到进程是如何创建、执行和消亡的,以及操作系统如何巧妙地决定哪个进程应该在何时获得CPU的青睐。让我们一起揭开操作系统神秘的面纱,发现那些隐藏在日常计算背后的精妙机制。
|
2月前
|
调度 开发者
深入理解操作系统之进程调度
在计算机科学领域,操作系统是核心的一环,它管理着计算机硬件资源,并提供接口供上层软件运行。本文将通过深入浅出的方式,探讨操作系统中至关重要的一个概念——进程调度。我们将从基础理论出发,逐步展开讲解进程调度的原理和实现,并配以实际代码示例,旨在帮助读者更好地理解和掌握这一主题。文章不仅适合初学者建立基础,也适合有一定基础的开发者深化理解。
|
2月前
|
算法 调度 UED
深入理解操作系统:进程管理与调度策略
【10月更文挑战第40天】在数字世界中,操作系统是连接硬件与软件的桥梁,它管理着计算机资源和提供用户服务。本文将深入探讨操作系统中的进程管理与调度策略,揭示它们如何协调多任务运行,保证系统高效稳定运作。通过代码示例,我们将展示进程创建、执行以及调度算法的实际应用,帮助读者构建对操作系统核心机制的清晰认识。
|
2月前
|
算法 调度 UED
深入理解操作系统:进程管理与调度策略
【10月更文挑战第34天】本文旨在探讨操作系统中至关重要的一环——进程管理及其调度策略。我们将从基础概念入手,逐步揭示进程的生命周期、状态转换以及调度算法的核心原理。文章将通过浅显易懂的语言和具体实例,引导读者理解操作系统如何高效地管理和调度进程,保证系统资源的合理分配和利用。无论你是初学者还是有一定经验的开发者,这篇文章都能为你提供新的视角和深入的理解。
47 3