一、实验目的和要求
要求了解操作系统的基本原理及基本概念,掌握实现各原理的算法,能结合实际开发工具模拟演示课程中涉及的算法,以达到深入掌握操作系统理论的目的。要求学生上机之前充分准备,给出算法的设计流程和详细代码;认真做实验,要求给出调试通过的可运行程序;认真解答思考题中的问题,记录实验中遇到的问题和解决方法;独立编写实验报告。
握操作系统的设备管理功能,熟悉移动臂调度算法,设计恰当的数据结构和算法,模拟实现移动臂调度算法。
二、实验方法与步骤(需求分析、算法设计思路、流程图等)
1.先来先服务算法
先来先服务算法中,磁盘臂是随机移动的,不考虑各I/O请求之间的相对次序和移动臂当前所处位置,特点是进程等待I/O请求的时间会很长,寻道性能较差。
简单来说,就按题目中所给的柱面依次进行到达,题目中是150,30,190,20,100,55,90,那就先去150,再绕回去30,再绕去190…等待。如图所示:
故移动臂移动柱面总数=(150-50)+(150-30)+(190-30)+(190-20)+(100-20)+(100-55)+(90-55)=710
2.最短查找时间优先算法
最短查找时间优先算法总是先执行查找时间最短的请求,与FCFS算法相比有较好的寻道性能。简单来说,就是先去距离近的,例如本题中,离50最近的是55,就先去55,离55最近的是30,就先去30,以此类推,如图所示:
故移动臂移动柱面总数=(55-50)+(55-30)+(30-20)+(90-20)+(100-90)+(150-100)+(190-150)=210
3.扫描算法
扫面柱面就是“撞到南墙才回头”,往一个方向扫柱面后,就一直往那个方向扫,直到那个方向的柱面都扫完了才往反方向扫,例如本题,50往55方向扫,55的下一步就是90,90的下一步就是100…直到190的下一步199,再往回扫。
注意,按照扫描算法规则,即使没有访问请求也须扫描到头,所以到达要求的190后还要扫到199。如图所示:
故移动臂移动柱面总数=(55-50)+(90-55)+(100-90)+(150-100)+(190-150)+(199-190)+(199-30)+(30-20)=328
4.电梯调度算法
电梯调度算法是扫描算法的一种改进,每次总是选择沿移动臂的移动方向最近的那个柱面,若同一个柱面上有多个请求,还需进行旋转优化。如果当前的移动方向上没有但相反方向有访问请求时,就改变移动臂的移动方向。
本例题中,电梯调度算法的图示情况如下:
相对于扫描算法来说,并没有扫到199,因为到达190后没有要求的柱面,所以就往相反方向扫描,就跟电梯一样,从1楼乘往18楼,如果中间楼层的人想搭电梯下楼,是要先等电梯到达18楼后再往下走。
移动臂移动柱面总数=(55-50)+(90-55)+(100-90)+(150-100)+(190-150)+(190-30)+(30-20)=310
5.循环扫描算法
循环扫描算法就更简单了,往一个方向扫描后,扫完了,直接重新从反方向的开始方向扫剩下的,如图所示:
移动臂移动柱面总数=(55-50)+(90-55)+(100-90)+(150-100)+(190-150)+(150-100)+(190-150)+(199-190)+(199-0)+(20-0)+(30-20)=378
三、实验原始纪录(源程序、数据结构等)
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<conio.h>
using namespace std;
struct node
{
int dat;
struct node* pre;
struct node* nex;
node(int x){pre=NULL;nex=NULL;dat=x;}
};
//插入访问请求位置为x的请求
node* Insert(node* head,int x)
{
if(head==NULL)
return new node(x);
node* q=new node(x);
node *p=head;
while(p->nex&&p->dat<x)
{
p=p->nex;
}
//cout<<"p:"<<p->dat<<endl;
if(p->dat>x)
{
q->pre=p->pre;
q->nex=p;
if(p->pre==NULL)
{p->pre=q;return q;}
p->pre->nex=q;
p->pre=q;
}
else
{
p->nex=q;
q->pre=p;
}
return head;
}
//打印请求序列
void print(node *head)
{
node *p=head;
while(p)
{
printf("%d ",p->dat);
p=p->nex;
}
printf("\n");
}
node* Find(node *head,int pos,bool fx)
{
node *p=head;
if(fx)
{
while(p&&p->dat<pos) p=p->nex;
return p;
}
else
{
while(p->nex&&p->nex->dat<=pos) p=p->nex;
return p;
}
}
//模拟左右移臂调度
node *shift(int *ans,int *pos,node *head,bool fx)
{
//cout<<*pos<<' '<<*ans<<endl;
node *p=Find(head,*pos,fx);
//cout<<"p:"<<p->dat<<endl;
if(p)
{
if(fx) *ans+=(p->dat-*pos);
else *ans+=(*pos-p->dat);
*pos=p->dat;
if(p->pre==NULL)
{
//cout<<'a'<<endl;
head=head->nex;
if(head) head->pre=NULL;
free(p);
}
else if(p->nex==NULL)
{
//cout<<'b'<<endl;
p->pre->nex=NULL;
free(p);
}
else
{
//cout<<'c'<<endl;
p->pre->nex=p->nex;
p->nex->pre=p->pre;
free(p);
}
}
else cout<<"已至边界!"<<endl;
return head;
}
int main()
{
int x,pos,ans=0;
node *head=NULL;
cout<<"输入一串访问申请,数字表示物理位置(以-1结束):"<<endl;
while(scanf("%d",&x)&&x!=-1)
head=Insert(head,x);
cout<<"输入你当前的位置:";
scanf("%d",&pos);
cout<<"用键盘A D键模拟移臂方向,用‘+ 访问位置’来添加新的任务"<<endl;
print(head);
while(head)
{
char ch;
ch=getch();
if(ch=='a'||ch=='A') head=shift(&ans,&pos,head,0);
else if(ch=='d'||ch=='D') head=shift(&ans,&pos,head,1);
else if(ch=='+')
{
cout<<'+'; //好看
scanf("%d",&x);
head=Insert(head,x);
}
else cout<<"麻烦认真一点输入好吗?"<<endl;
print(head);
}
cout<<"任务完成!"<<endl<<"历经长度为:"<<ans<<endl;
return 0;
}
四、实验结果及分析(计算过程与结果、数据曲线、图表等)
如图所示,算法正如开始时的模拟图运行,从而可以确定算法的正确性
五、实验改进与思考
今天我们做了操作系统实验,其主题为“移臂调度算法的模拟实现”,其主要可以分为扫描算法,最短查找时间优先算法,先来先服务算法,电梯调度算法,循环扫描算法。
磁盘是一种高速、大容量、旋转型、可直接存取的存储设备。它作为计算机系统的辅助存储器,担负者繁重的输入输出任务、在多道程序设计系统中,往往同时会有若干个要求访问磁盘的输入输出请求等待处理。系统可采用一种策略,尽可能按最佳次序执行要求访问磁盘的诸输入输出请求。这就叫驱动调度,使用的算法称为驱动调度算法。移臂调度算法是驱动调度技术中的算法,目的是减少为若干I/O请求服务所需消耗的总时间,从而提高系统效率。从而降低为若干个输入输出请求服务所需的总时间,从而提高系统效率。
通过本次实验,我加深对移臂调度算法的理解。并掌握操作系统中磁盘调度的原理及实现方法,提高了自己编程的能力,提高了综合运用专业课知识的能力。这次的实验有前几次实验的经历所以做起来更加的轻松了,但是程序仍然有很多改进的地方,资源可以更加节约,算法也还有优化的余地。这次实验也让我感觉到了算法才是程序的灵魂,没有好的算法就像巧妇难为无米之炊,即使有再好的工具和基本功没有算法和基本思想也是不可行的。