《操作系统》课程实验(五)
磁盘是可供多个进程共享的设备,当有多个进程都要求访问磁盘是,应采用一种最佳调度算法,以使各进程对磁盘的平均访问时间最小。目前最成用的磁盘调度算法有先来先服务(FCFS),最短寻道时间优先(SSTF),以及扫描算法(SCAN)。通过本实验可以加深理解有关磁盘调度的目标,并体会和了解最短寻道时间优先算法和扫描算法的具体实施办法。
- 从100#磁道开始,被访问的磁道号分别为:55,58,39,18,90,160,150,38,184。
- 要求用最短寻道时间优先算法的和扫描算法实现磁盘调度。
- 记录下每访问一个磁道磁头移动的磁道数,并计算平均寻道长度(平均移动磁道数)。
编程语言:Java
开发工具:IntelliJ IDEA
- 实验要求
分别用两种算法实现磁盘调度。在实验结果分析中,将比较结果以列表的形式表现出来。用数组(或链表)TR[ ]存储待访问磁道号,将每次磁头移动磁道数用数组AR[ ] 存储。输出结果应如下例:(注意空格)
150 | 50 |
160 | 10 |
,184 | 24 |
18,, | 166 |
38 | 20 |
39 | 1 |
55 | 16 |
58 | 3 |
90 | 32 |
平均寻道长度:35.8 |
- 实验代码
- 类名:Request //请求
public class Request {
private int id;//请求号,唯一标识一个请求
private int number;//欲访问的磁道号
private int flag;//是否已被调度的标记,初始为0,表示为被调度。
public Request(){//空白构造器
this.id=0;
this.number=0;
this.flag=0;
}
public Request(int id,int num){//带参构造器
this.id=id;
this.number=num;
this.flag=0;
}
public void setId(int id){
this.id=id;
}
//以下是一系列set和get方法
public int getId(){
return this.id;
}
public void setNumber(int number){
this.number=number;
}
public int getNumber(){
return this.number;
}
public void setFlag(int flag){
this.flag=flag;
}
public int getFlag(){
return this.flag;
}
}
- 类名:Diaodu //最短寻道
public class DiaoDu {
Work work;
Request[] request;
int begin;//磁头初始位置
DecimalFormat df = new DecimalFormat("0.000");
public DiaoDu(Work work){//构造器,接收一个作业
this.work=work;
request=work.getRandomRequest();
//磁头初始位置设为所允许访问磁道号范围的中间值。
//如若磁道访问允许范围为100~300,则磁头初始位置在200处。
begin=(work.getStart()+work.getEnd())/2;
}
public void SSTF(){//最短寻道优先
begin=(work.getStart()+work.getEnd())/2;
Request[] req=request;
System.out.println("磁道号区间:"+work.getStart()+"到"+work.getEnd());
System.out.println("磁头初始时所在磁道号:"+begin);
int t=0;
double sum=0;
System.out.println("请求号 被访问的下一个磁道号 移动距离");
for(int i=0;i<req.length;i++){
int temp=work.getEnd();
for(int j=0;j<req.length;j++){
if(Math.abs(req[j].getNumber()-begin)<temp&&req[j].getFlag()==0){
temp=Math.abs(req[j].getNumber()-begin);
t=j;
}
}
System.out.println("--"+req[t].getId()+"----------------"+req[t].getNumber()+"-----------------"+temp+"--");
begin=req[t].getNumber();
req[t].setFlag(1);
sum+=temp;
}
System.out.println("***********平均寻道长度为:"+df.format(sum/req.length)+"***********");
}
public void SCAN(){//扫描算法
begin=(work.getStart()+work.getEnd())/2;
Request[] req=request;
int direction;//磁头运动方向方向
System.out.println("设定磁头初始化运动方向(1:磁道号增大方向 -1:磁道号减小方向):");
direction=new Scanner(System.in).nextInt();
System.out.println("磁道号区间:"+work.getStart()+"到"+work.getEnd());
System.out.println("磁头初始时所在磁道号:"+begin);
if(direction==1)
System.out.println("磁头初始运动方向: 磁道号增大方向");
else
System.out.println("磁头初始运动方向: 磁道号减小方向");
Map<Integer,Request> map=new HashMap<Integer,Request>();
TreeSet<Integer> ts1=new TreeSet<Integer>();
TreeSet<Integer> ts2=new TreeSet<Integer>();
for(Request r:req){
if(r.getNumber()>=begin){
map.put(r.getNumber(), r);
ts1.add(r.getNumber());
}
else{
map.put(r.getNumber(), r);
ts2.add(r.getNumber());
}
}
System.out.println("请求号被访问的下一个磁道号移动距离");
double sum=0;
if(direction==1){
for(int temp:ts1){
System.out.println("--"+map.get(temp).getId()+"----------------"+temp+"-----------------"+Math.abs(temp-begin));
sum+=Math.abs(temp-begin);
begin=temp;
}
for(int temp:ts2.descendingSet()){
System.out.println("--"+map.get(temp).getId()+"----------------"+temp+"-----------------"+Math.abs(temp-begin));
sum+=Math.abs(temp-begin);
begin=temp;
}
}
else{
for(int temp:ts2.descendingSet()){
System.out.println("--"+map.get(temp).getId()+"----------------"+temp+"-----------------"+Math.abs(temp-begin));
sum+=Math.abs(temp-begin);
begin=temp;
}
for(int temp:ts1){
System.out.println("--"+map.get(temp).getId()+"----------------"+temp+"-----------------"+Math.abs(temp-begin));
sum+=Math.abs(temp-begin);
begin=temp;
}
}
System.out.println("***********平均寻道长度为:"+df.format(sum/req.length)+"***********");
}
}
- Work //扫描
public class Work {
private int start;//允许访问的磁道号范围的起始磁道号
private int end;//允许访问的磁道号范围的终止磁道号
//即请求可请求访问的磁道号在start与end之间
private int num;//所要产生的磁盘访问请求数量
public Work(){//不带参构造器
this.start=0;
this.end=0;
this.num=0;
}
public Work(int start,int end,int num){//带参构造器
this.start=start;
this.end=end;
this.num=num;
}
public int getStart(){
return this.start;
}
public int getEnd(){
return this.end;
}
public Request[] getRandomRequest() {//产生磁盘访问请求的方法
Request req[] = new Request[num];//数组声明num个请求
Random random = new Random();
Set<Integer> set = new HashSet<Integer>();
while (true) {//为num个请求依次生成要访问的磁道号,放入set集合
set.add((int) (random.nextInt(end - start) + start));
if (set.size() == num)
break;
}
int i = 0;
//将set集合中的数取出依次付给各请求。使用set的目的是让num个访问请求要访问的磁道号各不同。
for (int temp : set) {
req[i] = new Request(i + 1, temp);
i++;
}
return req;
}
}
- 类名:Main //主类
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
int start,end,num;
Scanner in=new Scanner(System.in);
System.out.println("设定磁道起止道号:");
System.out.print("起始道号:");
start=in.nextInt();
System.out.print("终止道号:");
end=in.nextInt();
System.out.print("输入磁盘访问的请求数:");
num=in.nextInt();
Work work=new Work(start,end,num);
DiaoDu diaodu=new DiaoDu(work);
System.out.println();
System.out.println("***********最短寻道时间优先调度法************");
diaodu.SSTF();
System.out.println();
System.out.println("****************扫描调度法*****************");
diaodu.SCAN();
}
}
- 实验截图