设计要求
题目
多道批处理系统的两级调度
要求概况
本课程设计要求模拟实现一个的多道批处理系统的两级调度。通过具体的作业调度、进程调度、内存分配等功能的实现,加深对多道批处理系统的两级调度模型和实现过程的理解。
具体要求
作业从进入系统到最后完成,要经历两级调度:作业调度和进程调度。作业调度是高级调度,它的主要功能是根据一定的算法,从输入井中选中若干个作业,分配必要的资源,如主存、外设等,为它们建立初始状态为就绪的作业进程。进程调度是低级调度,它的主要功能是根据一定的算法将CPU分派给就绪队列中的一个进程。
1. 假定某系统可供用户使用的主存空间共100KB,并有4台磁带机。主存分配采用可变分区分配方式且主存中信息不允许移动,对磁带机采用静态分配策略,作业调度分别采用最小作业优先算法,进程调度采用可抢占的最短进程优先算法。
2. 假定“预输入”程序已经把一批作业的信息存放在输入井了,并为它们建立了相应作业表。测试数据如下:
作业 | 到达时间 | 估计运行时间 | 内存需要 | 磁带机需要 |
JOB1 | 10:00 | 25分钟 | 15K | 2台 |
JOB2 | 10:20 | 30分钟 | 60K | 1台 |
JOB3 | 10:30 | 10分钟 | 50K | 3台 |
JOB4 | 10:35 | 20分钟 | 10K | 2台 |
JOB5 | 10:40 | 15分钟 | 30K | 2台 |
3. 分别在不同算法控制下运行设计的程序,依次显示被选中作业、内存空闲区和磁带机的情况。比较不同算法作业的选中次序及作业平均周转时间。
需求分析
从课程题目上进行分析,需要编写多道批处理的两级调度模拟器,其具备的功能有:在输入井中写入数据、设定相应的磁带机数量和内存块信息、用相应的调度算法进行作业和进程调度、显示运行全过程。
(1)输入作业:向输入井中预输入自定义作业,并验证作业的可执行性
(2)添加资源项:可向系统添加磁带机和内存块
(3)时间管理:显示当前时间,暂停和继续,设置一个单位的时间长度
(4)合并空间:可将所有的内存空间进行合并。
(5)选择算法:可以按照所需来调整调度算法
(6)动态显示数据:实时监控各个队列中的作业情况
系统设计
设计思想
使用java面向对象技术,对处理机、时间、作业、进程、输入井、后备队列、就绪队列、内存块、磁带机等“对象”都进行抽象化,用一个个“类”来模拟。
将上述的内容整合,让除处理机之外的类都能在处理机中相互协作或抑制,作业和进程的调度都要考虑内存块和磁带机的情况,并且能够对其进行更改数据。调度成功与否都会影响作业或进程所在的队列,以及各项资源数据。
系统编写一个时间类,时间的运走会触发两件事:进行执行或调度、更新显示内容。
使用Swing技术写界面,运用JFormDesigner工具进行拖动化设计。
时间类添加监听时间,监听时间的运行,检测到即更新swing界面显示内容。
以上实现模拟两级调度的过程。
模块层次图
模块解析
进程调度模块
作业调度模块
内存分配模块
时间管理模块
界面的设计
工具
JFormDesigner
界面外观
项目结构
关键代码
短进程优先
**
* 进程执行一个时间单位
*/
private void SPF() {
if (nowProess == null) {
if (jobs2.size() != 0) {
nowProess = jobs2.remove(0);
nowProess.setStatus('R');
System.out.println("时间:" + clock.getTime() + "|开始调用进程:" + nowProess.toString());
} else if (integerJobHashMap.size() == 0 && well.size() == 0) {
System.out.println("时间:" + clock.getTime() + "|任务完成");
System.out.println("________________以下是结果_________");
jobs3.sort(((o1, o2) ->o1.getID()-o2.getID()));
for(int i=0;i<=jobs3.size()-1;i++){
System.out.println(jobs3.get(i).toString());
}
run = false;
return;
} else {
System.out.println("时间:" + clock.getTime() + "|无进程可调度");
return;
}
}
System.out.println("时间:" + clock.getTime() + "|正在执行:" + nowProess.toString());
nowProess.setTime(nowProess.getTime() + 1);
if (nowProess.getTime() == nowProess.getServiceTime()) {
//已经执行完毕
nowProess.setFinishTime(clock.getTime());
nowProess.setRoundTime(nowProess.getFinishTime() - nowProess.getSubmitTime()+1);
nowProess.setAveRoundTime((double) nowProess.getRoundTime() / nowProess.getServiceTime());
nowProess.setStatus('F');
System.out.println("时间:" + clock.getTime() + "|执行完毕:" + nowProess.toString());
//释放空间的占用
integerJobHashMap.remove(nowProess.getID());
nowProess.setTapeGet(false);
tapes += nowProess.getTapeNeeded();
Block block = integerBlockHashMap.get(nowProess.getBlockID());
Queue<Integer> queue = block.getJobIDs();
queue.remove(nowProess.getID());
block.setJobIDs(queue);
block.setRemainSize(block.getRemainSize() + nowProess.getSize());
integerBlockHashMap.put(block.getID(), block);
for (int j = 0; j <= jobs1.size() - 1; j++) {
if (jobs1.get(j).getID() == nowProess.getID()) {
jobs1.remove(j);
}
}
jobs3.add(nowProess);
nowProess = null;
BF();
}
}
短作业优先
/**
* 作业调度
*/
private void SJF() {
if (jobs.size() == 0) {
System.out.println("时间:" + clock.getTime() + ":无作业需要调度");
}
jobs.sort((o1, o2) -> o1.getServiceTime() - o2.getServiceTime());
for (int i = 0; i <= jobs.size() - 1; i++) {
nowJob = jobs.remove(0);
jobs1.add(nowJob);
//尝试分配
integerJobHashMap.put(nowJob.getID(), nowJob);
BF();
}
nowJob = null;
}
内存块分配BF算法
/**
* 最佳适应
*/
public void BF() {
if (integerJobHashMap.size() >= 1 && integerBlockHashMap.size() >= 1) {
//按作业调度顺序来分配
int jobID;
for (int i = 0; i <= jobs1.size() - 1; i++) {
jobID = jobs1.get(i).getID();
if (integerJobHashMap.get(jobID) != null &&
integerJobHashMap.get(jobID).getState() == 0 &&
!integerJobHashMap.get(jobID).isTapeGet()) {
JOB job = integerJobHashMap.get(jobID);
System.out.println("时间:" + clock.getTime()+"选中作业:" + job.toString());
//找到最佳适应的块
int bestFitBlockID = -1;
for (int blockID = 0; blockID <= integerBlockHashMap.size() - 1; blockID++) {
Block block = integerBlockHashMap.get(blockID);
if (block.getRemainSize() - job.getSize() >= 0) {
if (bestFitBlockID == -1) bestFitBlockID = blockID;
else if (block.getRemainSize() <= integerBlockHashMap.get(bestFitBlockID).getRemainSize()) {
bestFitBlockID = blockID;
}
}
}
//操作部分
if (bestFitBlockID != -1 && job.getTapeNeeded() <= tapes) {
Block block;
block = integerBlockHashMap.get(bestFitBlockID);
block.setRemainSize(block.getRemainSize() - job.getSize());
block.addaJobID(jobID);
job.setState(1);
job.setBlockID(bestFitBlockID);
job.setTapeGet(true);
tapes -= job.getTapeNeeded();
integerBlockHashMap.put(bestFitBlockID, block);
integerJobHashMap.put(jobID, job);
System.out.println("时间:" + clock.getTime()+"作业分配成功:" + job.toString());
//抢占(排好队等待调度)
if(nowProess!=null && job.getServiceTime()< nowProess.getServiceTime()){
nowProess.setStatus('W');
jobs2.add(0,nowProess);
jobs2.add(0,job);
nowProess = null;
System.out.println("时间:" + clock.getTime()+"抢占成功"+job);
}else {
jobs2.add(job);
jobs2.sort((o1, o2) -> o1.getServiceTime()-o2.getServiceTime());
}
} else {
System.out.println("时间:" + clock.getTime()+"作业分配失败:" + job.toString());
System.out.println("时间:" + clock.getTime()+"原因:空间不够或磁带不够");
}
}
}
}
}
内存块合并算法
**
* 合并空间
*/
public void spaceToMerge() {
if (integerBlockHashMap.size() > 0) {
int size1 = integerBlockHashMap.size();
for (int blockID = 0; blockID <= size1 - 1; blockID++) {
if (integerBlockHashMap.get(blockID).getRemainSize() > 0) {
int finalBlockID = blockID;
while (finalBlockID < size1 - 1
&& integerBlockHashMap.get(finalBlockID + 1).getRemainSize() == integerBlockHashMap.get(finalBlockID + 1).getSize()) {
finalBlockID++;
}
if (finalBlockID != blockID) {
int size = 0;
Block newBlock = new Block();
newBlock.setStartAddress(integerBlockHashMap.get(blockID).getEndAddress() - integerBlockHashMap.get(blockID).getRemainSize() + 1);
for (int startID = blockID; startID <= finalBlockID; startID++) {
Block block = integerBlockHashMap.get(startID);
size += block.getRemainSize();
block.setSize(block.getSize() - block.getRemainSize());
block.setRemainSize(0);
integerBlockHashMap.put(block.getID(), block);
if (startID == finalBlockID) {
newBlock.setSize(size);
newBlock.setRemainSize(size);
}
}
newBlock.setID(integerBlockHashMap.size());
newBlock.setEndAddress(newBlock.getStartAddress() + newBlock.getSize() - 1);
integerBlockHashMap.put(integerBlockHashMap.size(), newBlock);
}
blockID = finalBlockID;
}
}
}
}
总结
对swing界面的刷新采用了响应式的设计,即在Clock时钟类中运用PropertyChangeSupport类,对每一次time的增加产生一定的行为。提升了程序执行的效率,也提升了数据呈现的精确度。