写在前面
欢迎讨论。
问题描述
用JAVA同步方法实现磁头引臂调度问题,采用SCAN算法。
要求:(1) 给出核心调度解法,用JAVA类实现,其中包含require(dest)和release()两个同步方法;(2) 创建若干线程或进程,分别提出某一磁道上某个磁盘块的访问请求,给出调度结果。
说明:(1)假定盘面上共有200个磁道,由外向内依次编号0,…,199,盘面只有一个移动磁头; (2)模拟访问磁盘时打印出磁道编号,并延迟一段时间以表示磁盘I/O操作时间;
Java实现
Device
用于模拟向磁盘申请访问的设备,向磁盘提出申请访问请求
Disk
用于模拟磁盘,scan方法在其中实现
Main
启动线程
Device
类
/**
* @Description 用于模拟向磁盘申请访问的设备
*/
public class Device implements Runnable {
Disk disk;
public Device(Disk disk) {
this.disk = disk;
}
@Override
public void run() {
while (disk.getTimes()>0)
{
int max=199,min=0;
int randomDest = (int) (Math.random()*(max-min)+min);
disk.require(randomDest);//申请磁道
try {
Thread.sleep(1500);//运行一段时间后再次申请
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Disk
类
/**
* @Description 此类用于模拟磁盘
*/
public class Disk implements Runnable {
int[]dests;//磁道
int position;//当前位置
int flag;//移动方向,1下标增大,-1下标减小
int times;
public synchronized int getTimes() {
return times;
}
public Disk(int position, int flag) {
this.position = position;
this.flag = flag;
dests=new int[200];
times=10;
System.out.println("磁头引臂当前磁道:"+position+" 移动方向:"+flag);
}
@Override
public void run() {
//等待设备启动和申请
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//开始检查设备的申请并提供访问服务
boolean result=false;
while (times>0)
{
//为了使程序停止,设定可访问次数
try {
result=manage();//分配磁道,访问磁道
} catch (InterruptedException e) {
e.printStackTrace();
}
if (result)
{
times--;
}
}
System.out.println("结束全部访问...");
}
/**
* @Description 用于模拟磁道的调度
* @return 进行了一次传输返回true,无传输返回false
* @throws InterruptedException
*/
private synchronized boolean manage() throws InterruptedException {
int nextDest= scan();//利用scan找到下一个应该访问的磁道
if(nextDest!=-1)
{
using(nextDest);//移动磁头引臂访问磁道
release();//释放
return true;
}
else
{
//System.out.println("无人访问,磁盘暂时休息...");
return false;
}
}
/**
* @Description 外部设备(cpu等)申请访问的磁道编号
* @param dest 申请访问的磁道编号
*/
void require(int dest)
{
System.out.println("申请了磁道:"+dest);
dests[dest]++;
}
/**
* @Description 采用scan算法计算引臂应移动到的位置
* @return 有磁道被申请访问时,返回磁道编号,没有时返回-1
*/
private int scan()
{
int next=-1;
next=hasNext();
if (next!=-1)
{
//当前方有磁道被申请
return next;
}
else
{
//前方无磁道被申请,查看反向
flag=-flag;
next=hasNext();
if(next!=-1)
{
//反向上有磁道被申请
return next;
}
}
return -1;
}
/**
* @Description 模拟磁盘被使用
* @param dest 申请访问的磁道编号
* @throws InterruptedException
*/
private synchronized void using(int dest) throws InterruptedException {
int d=Math.abs(position-dest);
position=dest;
System.out.println("正在访问磁道:"+dest+" (移动了"+d+"个磁道)");
//模拟访问过程
try {
Thread.sleep(1000);
}catch (Exception e)
{
}
return;
}
/**
* @Description 用于磁道的释放
*/
private synchronized void release()
{
dests[position]--;
System.out.println("释放了磁道:"+position);
}
/**
* @return 引臂移动方向上有磁道被申请,返回最近的磁道编号,无磁道被申请,返回-1
*/
private int hasNext()
{
for(int i=position;i<dests.length&&i>0;i+=flag)
{
if(dests[i]>0)
{
return i;
}
}
return -1;
}
}
Main
类
public class Main {
public static void main(String[] args) {
int threadNumber=6;//线程数
int deviceNumber=threadNumber-1;//可能申请磁盘的设备数
//磁盘、设备、线程
Disk disk=new Disk(100,-1);
Thread[]threads=new Thread[threadNumber];
Device[]devices=new Device[deviceNumber];
threads[0]=new Thread(disk,Integer.toString(0));
for (int i=1;i<threadNumber;i++)
{
devices[i-1]=new Device(disk);
threads[i]=new Thread(devices[i-1],Integer.toString(i));
}
//启动线程
for (int i=0;i<threadNumber;i++)
{
threads[i].start();
}
}
}
进阶-双引臂SCAN调度问题
仍假定盘面上共有200个磁道,由外向内依次编号0,…,199,同一引臂上两个磁头head1和head2,二者相距100个磁道,复位时head1位于磁道0,head2位于磁道100,head1负责0…99磁道上的I/O请求,head2负责100…199磁道上的I/O请求。例如,当head1位于磁道35时,head2位于磁道135。
仅需对部分函数修改。
对hasNext()
函数的修改
/**
* @return 引臂移动方向上有磁道被申请,返回最近的磁道编号,无磁道被申请,返回-1
*/
private int hasNext()
{
int head1;//第一个磁头
int head2;//第二个磁头
if(position<dests.length/2)
{
head1=position;
head2=position+(dests.length/2);
}
else
{
head1=position-(dests.length/2);
head2=position;
}
//System.out.println(head1+" "+head2);
for(;head2<dests.length&&head1>=0;head1+=flag,head2+=flag)
{
if(dests[head1]>0)
{
return head1;
}
else if (dests[head2]>0)
{
return head2;
}
}
return -1;
}
对using()
函数的修改
/**
* @Description 模拟磁盘被使用
* @param dest 申请访问的磁道编号
* @throws InterruptedException
*/
private synchronized void using(int dest) throws InterruptedException {
int d=0;
if((dest-(dests.length/2))*(position-(dests.length/2))<0)
{
//说明要访问的磁道与上次访问的位置不在一侧
if(dest>(dests.length/2))
{
//上次访问的位置在0-99
position=position+(dests.length/2);
}
else
{
//上次访问的位置在100-199.这次需要访问的位置在0-99
position=position-(dests.length/2);
}
}
d=Math.abs(position-dest);
position=dest;
System.out.println("正在访问磁道:"+dest+" (移动了"+d+"个磁道)");
//模拟访问过程
try {
Thread.sleep(1000);
}catch (Exception e)
{
}
return;
}
不足
代码中磁头和磁盘耦合度过高。
解决办法可以是磁头可以抽象出类来或者磁头用数组保存磁头的移动可以单独设计成函数。