操作系统实验
1. 实践基础要求
以计算机操作系统原理为指导,利用面向对象程序设计技术仿真 OS 内核的作业管理、连续内存管理、页式虚存管理、进程同步与互斥的 API 功能,可视化显示操作系统工作过程,完成操作系统课程设计的程序设计、开发、测试,答辩以及撰写实践报告。
注意:本课程设计必须完成基础要求,扩展设计达到选题要求。
1.1 裸机仿真设计基础要求
◆基础硬件部件:
CPU、内存、时钟中断、输入输出设备中断、地址变换机构(MMU);◆扩展硬件部件:缺页中断;
◆CPU 与寄存器的仿真设计
CPU 可抽象为一个类,名称:CPU。关键寄存器可抽象为类的属性,至少包括:程序计数器(PC)、指令寄存器(IR)、状态寄存器(PSW)等,寄存器内容的表示方式自行设计。
CPU 寄存器现场保护、现场恢复操作可封装为进程调度类的方法,供进程切换、CPU
模式切换方法调用。
◆时钟中断、作业请求的输入输出中断、缺页中断的仿真
仿真系统时钟中断、输入事件中断、输出事件中断、缺页中断。
分别用 5 个线程仿真实现,线程类名称固定,分别叫 ProcessScheduling_thread、
JobRequest_thread、InputBlock_thread、OutputBlock_thread、PageInterruption_thread
每个线程中按照要求设置激活时间的长短
(1)ProcessScheduling_thread:用于进程的调度,设置线程每隔 1 秒计时 1 次,CPU执行 1 条指令,也就是假设计算机 CPU 在 1 秒(s)发生一次时钟硬件中断,执行 1 条指令。
(2)JobRequest_thread:用于新作业请求中断的仿真,常用鼠标双击事件而发生:假设计算机每 10 秒(s)查询一次外部是否有新作业的执行请求,在“并发作业请求文件”中判读是否有新进程请求运行。
(3)InputBlock_thread:阻塞队列的唤醒线程。外设输入变量造成进程进入阻塞态,如键盘给变量赋值
(4)OutputBlock_thread:阻塞队列的唤醒线程。外设输出变量造成进程进入阻塞态,如显示器显示
(5)PageInterruption_thread:选题为“虚页管理仿真”的考虑,其他选题不考虑。◆内存:共 16KB,每个物理块大小 1024B,共 16 个物理块。
假设不考虑 OS 内核所占内存空间‘
用位示图实现内存管理。可以假设基础存储单元是 100B,每个物理块占用 10 个基础存储单元。
选题 1:用内存的连续动态分配,假设每条“用户态计算操作语句或者函数”类型的指令占用 100B,在进程创建时动态计算所创建进程所占用内存大小。每个进程的逻辑地址、物理地址均连续,物理地址的基地址可以不同;
选题 2:内存用虚页管理,将每个物理块假设为 1 页帧,共 16 页。逻辑地址(物理地址)共 14 位二进制表示,其中 4 位表示页号,10 位表示页内地址;测试数据给出十进制的逻辑地址表示。采用固定分配和局部替换策略,每个用户进程分配内存大小为 4 页(块);用户进程最高并发度为 4;不考虑内存缓冲区缓冲区;磁盘交换区大小每个用户进程 4 页(块)。
地址变换过程(MMU)需要在界面上显示并详细记录过程保存到 ProcessResults-???-
算法名称代号.txt 文件中。???表示数字,为每次运行完成所有进程的总分钟数。
例如:测试输入数据是 input1 中的数据文件,用 LZ(时间片轮转)算法完成机器调度所有作业,总运行分钟数是 166 秒,保存进程运行输入输出以及调度过程中状态变化、统计数据等所有信息,保存到 ProcessResults-166-LZ.txt 文件,保存到 output1 子文件夹。
◆硬盘:选题为“虚页管理仿真”的考虑磁盘交换区仿真,磁盘交换区大小每个用户进程 4 页(块)。其他选题不需要考虑。
1.2 并发作业请求文件(jobs-input.txt)的设计
◆每个作业相当于用户提交给操作系统运行的可执行程序。本实验考虑作业调度、内存分配回收,进程管理;
◆创建 input 子文件夹,保存 jobs-input.txt 以及用户程序指令文件。本次实验有两组测试输入数据,分别放在 input1、input2 子文件中。
input1 子文件:选题 1 的同学使用;Input2 子文件:选题 2 的同学使用;
◆jobs-input.txt 文件格式固定,由教师统一提供,初始 5 个作业。一行代表一个作业请求,学生测试程序时可以增加新作业条目;
◆jobs-input.txt 文件内容:作业序号(JobsID)
作业优先级(Priority)作业请求时间(InTimes)
作业包含的程序指令数目(InstrucNum)
◆仿真程序开始运行时,开始按秒计时(不要用系统时间,用自己的计时器计时)。将jobs-input.txt 文件一次性读入一个临时数组。JobInput_thread 类每 10 秒(s)查询临时数组,根据当前计时器时间,通过判断与作业请求时间(InTimes)(单位为秒)中请求时间的匹配程度,判断该时刻是否有作业请求。如果有,加入作业后备队列,并根据作业编号找到该作业程序指令文件(与 jobs-input.txt 文件在同一目录),并将其内容保存到相应数据结构中。
◆在界面上需要设计一个作业实时请求接收按钮,随时接收该时刻产生的新作业并加入到作业后备队列;
1.3 用户程序指令文件的设计
◆用户程序指令文件是每个作业要执行的程序指令集合。每个作业的指令类型由本文档给出。
◆每个作业程序段指令包括 4 类,有语句和函数类型,统一保存在 input1 和 input2 子文件夹中。每个用户程序指令文件名用“作业序号(JobsID)”来命名。具体包括:
指令段编号(Instruc_ID)
用户程序指令的类型(Instruc_State)
用户程序指令访问的逻辑地址(L_Address)说明:
★本试验假设 CPU 执行用户态每段指令,在执行一段机器指令时不可以中断。
★指令编号(Instruc_ID):作业创建进程以后,进程所执行用户程序段指令序号,从1 开始计数。
★根据 Instruc_State 类型,每条指令运行或者唤醒时间(InRunTimes)有确定值,不需要输入;
★每条指令的类型标志为 Instruc_State:
0 表示用户态计算操作语句。进程正常调度,当时间片到时,进程切换;执行该指令需要 InRunTimes=1s;
1 表示用户态计算操作函数。进程转向执行函数指令。进程调度,当时间片到时,进程切换;执行该指令需要 InRunTimes=2s;
2 表示键盘输入变量语句。发生系统调用,CPU 进行模式切换,运行进程进入阻塞态;值守的键盘操作输入模块接收输入变量或输出变量内容,InRunTimes=2s 后完成输入,产生硬件终端信息号,阻塞队列 1 的队头节点出队,进入就绪队列;InputBlock_thread 类在 2s以后自动唤醒该进程;
3 屏幕输出显示语句。发生系统调用,CPU 进行模式切换,运行进程进入阻塞态;值守的屏幕显示模块输出变量内容,InRunTimes=3s 后完成显示,产生硬件终端信息号,阻塞队列 2 的队头节点出队,进入就绪队列;OutputBlock_thread 类在 3s 以后自动唤醒该进程;
★用户程序指令访问的逻辑地址(L_Address),由 input1 子文件、input2 子文件分别给出。用十进制表示。需要设计 MMU 类实现逻辑地址转换为物理地址。
选题 1:L_Address 表示每个用户进程所访问的逻辑地址;
选题 2:L_Address 表示每个用户进程所访问的逻辑地址,需要计算页号和页内偏移。MMU 类中需要包含名为 PageTableCreate( )函数,函数入口参数自行定义,实现页表生成。
★如果按界面上实时作业请求按钮:可以随机在已产生的指令文件中选择一个重新执行。
1.4 作业运行及调度详细记录的文件保存
◆作业和进程调度模块用单独的线程或计时器实现。需要重点注意的是:不是每次发生时钟中断都要进行进程调度。
◆时间片计算:进程调度最小时间片 2s。
◆进程调度算法:必须完成的调度算法为静态优先数调度算法(代号 JTYX)。扩展算法在选题要求中给出。
◆优先数越小,优先级越高。
◆程序要求界面可视化显示作业请求与进程调度过程。同时将调度过程以文件形式保存。界面显示和文件保存的信息要清晰、完整、可读;
◆作业调度、进程调度运行完成以后,运行记录保存到 ProcessResults-???-算法名称代号.txt 文件。???表示数字,为每次运行完成所有进程的总分钟数。例如:测试输入数据是 input1 中的数据文件,用 JTYX(静态优先数调度)算法完成机器调度所有作业,总运行分钟数是 166 秒,保存进程运行输入输出以及调度过程中状态变化、统计数据等所有信息,保存到 ProcessResults-166-JTYX.txt 文件,该保存到 output1 子文件夹。
保存内容至少包括:进程 ID、作业到达时间、作业运行时间、作业结束时间、作业中每条指令 ID、指令内容、指令状态转换的时间、CPU 寄存器变化情况、进程 PCB 信息等状态变化信息以及进程调度的周转时间等评价类数据。本次实验与 input1、input2 子文件测试数据对应的输出文件夹分别保存 output1、output2。该文件设计需要强调可读性与可分析性。
◆ProcessResults-???-算法名称代号.txt 文件内容的格式如下:(1)输出包括两段信息,分别为:进程调度事件:状态统计信息
(2)进程调度事件信息段的输出信息,每行有时间信息,按照时间顺序,记录发生进程调度事件、进程就绪队列、进程阻塞队列等的状态。
运行截图:
代码
项目结构:
CPU.java
public class CPU {
public static int CPUtime;//CPU当前时间
private int PC = 0;//程序计数器,初始值设为0,PC指向下一条指令
private int IR;//指令寄存器
private String PSW;//状态寄存器,0=运行,1=就绪,2=阻塞
private int mode = 0;//CPU模式,0=核心态,1=用户态
private boolean ifCloseInterrupt = false;//是否关中断,true=关中断(CPU处于核心态),false=未关中断(CPU处于用户态)
private boolean ifBusy = false;//CPU是否忙碌,true=忙碌,false=空闲
public Process workingProcess = null;//CPU当前正在运行的进程
public int timeSlice = 0;//当前所用的时间片剩余时间
public static int timeSliceSize = Main.timeSliceSize1;//当前所有时间片的规格
public void SetTime(int time) {
CPUtime = time;
}
public int GetTime() {
return CPUtime;
}
public void SetCPUBusyState(boolean ifbusy) {
this.ifBusy = ifbusy;
}
public boolean GetCPUBusyState() {
return ifBusy;
}
public boolean GetifCloseInterrupt() {
return this.ifCloseInterrupt;
}
public boolean GetifBusy() {
return this.ifBusy;
}
public int GetCPUMode() {
return mode;
}
public void SwitchCPUMode() {
//0=核心态,1=用户态
//将CPU当前的状态转换到另一个状态
if (this.mode == 0) {
//核心态转用户态
this.mode = 1;
//开中断
this.ifCloseInterrupt = false;
} else {
//用户态转核心态
this.mode = 0;
//关中断
this.ifCloseInterrupt = true;
}
}
public void SetPC(int pc) {
this.PC = pc;
}
public int GetPC() {
return this.PC;
}
public void SetIR(int ir) {
this.IR = ir;
}
public int GetIR() {
return this.IR;
}
public void SetPSW(String psw) {
this.PSW = psw;
}
public String GetPSW() {
return this.PSW;
}
}
PCB.java
import java.util.ArrayList;
import java.util.LinkedList;
public class PCB {
public int ProID;//进程编号
public int Priority;//进程优先数[1...5],优先数越小,优先级越高
public int InTimes;//进程创建时间
public int EndTimes;//进程结束时间
public String PSW;//进程状态,0=运行,1=就绪,2=阻塞
public int RunTimes;//进程运行时间
public int TurnTimes;//进程周转时间统计
public int InstrucNum;//进程包含的指令数目
public int PC;//程序计数器信息
public int IR;//指令寄存器信息
public static final ArrayList<PCB> PCBs = new ArrayList<>();//PCB池
public static int lastEndTime = 0;//用于记录最后一个进程被撤销的时间,用于最后的输出文件的命名
public int inRQ = 0;//记录进入RQ次数,用于MLFQ
public static final LinkedList<BlockingQueue> Blockingqueue1 = new LinkedList<>();//阻塞队列1,用于指令2
public static final LinkedList<BlockingQueue> Blockingqueue2 = new LinkedList<>();//阻塞队列2,用于指令3
public static final LinkedList<BlockingQueue> Blockingqueue3 = new LinkedList<>();//阻塞队列3,用于指令4
public static final LinkedList<BlockingQueue> Blockingqueue4 = new LinkedList<>();//阻塞队列4,用于指令5
public static final LinkedList<BlockingQueue> Blockingqueue5 = new LinkedList<>();//阻塞队列5,用于指令6
public PCB(int id, int priority, int intimes, int instructnum, String psw) {
//PCB类的构造函数
ProID = id;
Priority = priority;
InTimes = intimes;
InstrucNum = instructnum;
PSW = psw;
}
public PCB() {
}
public static int fromIDtoBQnum(int id, int BQtype) {
//通过进程的id返回BlockingQueue的位置
int i = 0;
if (BQtype == 1) {
i = 0;
for (BlockingQueue t : Blockingqueue1) {
if (t.BqNum == id) {
return i;
} else {
i++;
}
}
} else if (BQtype == 2) {
for (BlockingQueue t : Blockingqueue2) {
if (t.BqNum == id) {
return i;
} else {
i++;
}
}
} else if (BQtype == 3) {
for (BlockingQueue t : Blockingqueue3) {
if (t.BqNum == id) {
return i;
} else {
i++;
}
}
} else if (BQtype == 4) {
for (BlockingQueue t : Blockingqueue4) {
if (t.BqNum == id) {
return i;
} else {
i++;
}
}
} else if (BQtype == 5) {
for (BlockingQueue t : Blockingqueue5) {
if (t.BqNum == id) {
return i;
} else {
i++;
}
}
}
return i;
}
public static void joinBQ(int num, int BQtype, int time)//位置编号,进入阻塞队列的序号1\2\3\4\5,进入时间
{
switch (BQtype) {
case 1: {
BlockingQueue bq = new BlockingQueue(num, time);//建立一个临时的队列结点用于加入阻塞队列1中
Blockingqueue1.add(bq);
InandOutput.joinBQ(num, 1, time);
break;
}
case 2: {
BlockingQueue bq = new BlockingQueue(num, time);//建立一个临时的队列结点用于加入阻塞队列2中
Blockingqueue2.add(bq);
InandOutput.joinBQ(num, 2, time);
break;
}
case 3: {
BlockingQueue bq = new BlockingQueue(num, time);//建立一个临时的队列结点用于加入阻塞队列3中
Blockingqueue3.add(bq);
InandOutput.joinBQ(num, 3, time);
break;
}
case 4: {
BlockingQueue bq = new BlockingQueue(num, time);//建立一个临时的队列结点用于加入阻塞队列4中
Blockingqueue4.add(bq);
InandOutput.joinBQ(num, 4, time);
break;
}
case 5: {
BlockingQueue bq = new BlockingQueue(num, time);//建立一个临时的队列结点用于加入阻塞队列5中
Blockingqueue5.add(bq);
InandOutput.joinBQ(num, 5, time);
break;
}
}
}
public void quitRQ(int nowTime) {
//提供的改造后接口,多级反馈队列实现进行封装
int pos = -1;
int[] qType = {-1};//qType引用传递返回在几号队列
pos = MLFQ.fromIDtoRQnum(this.ProID, qType);
//System.out.print("RQ:");
if (qType[0] == 1) {
this.TurnTimes += nowTime - MLFQ.Readyqueue1.get(pos).RqTime + 1;//加上这一段的中转时间
//System.out.println(this.TurnTimes+"\t"+nowTime+"\t"+MLFQ.Readyqueue1.get(pos).RqTime);
MLFQ.Readyqueue1.remove(pos);//在RQ1里找到这个结点,并删除
InandOutput.quitRQ(this.ProID, 1, nowTime);
} else if (qType[0] == 2) {
this.TurnTimes += nowTime - MLFQ.Readyqueue2.get(pos).RqTime + 1;//加上这一段的中转时间
//System.out.println(this.TurnTimes+"\t"+nowTime+"\t"+MLFQ.Readyqueue2.get(pos).RqTime);
MLFQ.Readyqueue2.remove(pos);//在RQ2里找到这个结点,并删除
InandOutput.quitRQ(this.ProID, 2, nowTime);
} else if (qType[0] == 3) {
this.TurnTimes += nowTime - MLFQ.Readyqueue3.get(pos).RqTime + 1;//加上这一段的中转时间
//System.out.println(this.TurnTimes+"\t"+nowTime+"\t"+MLFQ.Readyqueue3.get(pos).RqTime);
MLFQ.Readyqueue3.remove(pos);//在RQ3里找到这个结点,并删除
InandOutput.quitRQ(this.ProID, 3, nowTime);
} else
System.out.println("Error!");
}
//因为每一次quitRQ后都会花1s进入运行态,因此计算时间的时候需要++,每一次quitBQ后会立即joinRQ,因此有1s的时间被重复统计,因此计算时间的时候需要--
public void quitBQ(int BQtype, int nowTime)//从何BQ退出,退出时间
{
//System.out.print("BQ:");
switch (BQtype) {
case 1: {
this.TurnTimes = this.TurnTimes + nowTime - Blockingqueue1.get(fromIDtoBQnum(this.ProID, 1)).BqTime - 1;//加上这一段的中转时间
//System.out.println(this.TurnTimes+"\t"+nowTime+"\t"+Blockingqueue1.get(fromIDtoBQnum(this.ProID,1)).BqTime);
Blockingqueue1.remove(fromIDtoBQnum(this.ProID, 1));//从BQ1里找到这个结点的位置,并删除
InandOutput.quitBQ(this.ProID, 1, nowTime);
break;
}
case 2: {
this.TurnTimes = this.TurnTimes + nowTime - Blockingqueue2.get(fromIDtoBQnum(this.ProID, 2)).BqTime - 1;//加上这一段的中转时间
//System.out.println(this.TurnTimes+"\t"+nowTime+"\t"+Blockingqueue2.get(fromIDtoBQnum(this.ProID,2)).BqTime);
Blockingqueue2.remove(fromIDtoBQnum(this.ProID, 2));//从BQ2里找到这个结点的位置,并删除
InandOutput.quitBQ(this.ProID, 2, nowTime);
break;
}
case 3: {
this.TurnTimes = this.TurnTimes + nowTime - Blockingqueue3.get(fromIDtoBQnum(this.ProID, 3)).BqTime - 1;//加上这一段的中转时间
//System.out.println(this.TurnTimes+"\t"+nowTime+"\t"+Blockingqueue3.get(fromIDtoBQnum(this.ProID,3)).BqTime);
Blockingqueue3.remove(fromIDtoBQnum(this.ProID, 3));//从BQ3里找到这个结点的位置,并删除
InandOutput.quitBQ(this.ProID, 3, nowTime);
break;
}
case 4: {
this.TurnTimes = this.TurnTimes + nowTime - Blockingqueue4.get(fromIDtoBQnum(this.ProID, 4)).BqTime - 1;//加上这一段的中转时间
//System.out.println(this.TurnTimes+"\t"+nowTime+"\t"+Blockingqueue4.get(fromIDtoBQnum(this.ProID,4)).BqTime);
Blockingqueue4.remove(fromIDtoBQnum(this.ProID, 4));//从BQ4里找到这个结点的位置,并删除
InandOutput.quitBQ(this.ProID, 4, nowTime);
break;
}
case 5: {
this.TurnTimes = this.TurnTimes + nowTime - Blockingqueue5.get(fromIDtoBQnum(this.ProID, 5)).BqTime - 1;//加上这一段的中转时间
//System.out.println(this.TurnTimes+"\t"+nowTime+"\t"+Blockingqueue5.get(fromIDtoBQnum(this.ProID,5)).BqTime);
Blockingqueue5.remove(fromIDtoBQnum(this.ProID, 5));//从BQ5里找到这个结点的位置,并删除
InandOutput.quitBQ(this.ProID, 5, nowTime);
break;
}
}
}
}
class BlockingQueue {
//阻塞队列的定义
public final int BqNum;//位置编号
public final int BqTime;//进程进入阻塞队列的时间
public BlockingQueue(int ProID, int InTimes) {
//为新进入阻塞队列的进程设置位置编号(进程的ProID)与进入就绪队列的时间
BqNum = ProID;
BqTime = InTimes;
}
}
Init.java
import org.jcp.xml.dsig.internal.SignerOutputStream;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
public class Init {
public static boolean Initialize(String txtPath) {
if (!JobsArray.ReadWorks(txtPath)) {
return false;
}
return true;
}
}
class JobsArray {
//作业后备队列
public static final ArrayList<JobsNode> array = new ArrayList<>();//保存所有请求的作业
public static final ArrayList<JobsNode> arrayForUse = new ArrayList<>();//用于对这些作业的操作
public static boolean ReadWorks(String txtPath) {
//读取txt文件中的作业
try (
FileReader fileReader = new FileReader(txtPath);
BufferedReader bufferedReader = new BufferedReader(fileReader)
) {
String line = new String();
String[] lines;//用于分割每个作业的序号、优先级、请求时间、程序指令数目
while ((line = bufferedReader.readLine()) != null) {
//扫描txt文件中剩下的所有行
lines = line.split(",");//按照","进行分割
JobsNode newNode = new JobsNode();
//序号、优先级、请求时间、程序指令数目
newNode.JobsID = Integer.parseInt(lines[0]);
newNode.Priority = Integer.parseInt(lines[1]);
newNode.InTimes = Integer.parseInt(lines[2]);
newNode.InstrucNum = Integer.parseInt(lines[3]);
//读取这个作业的指令
if (!ReadInstruc(newNode)) {
//未成功读取这个作业的指令
InandOutput.FailedReadInstruction(newNode.JobsID);
return false;
} else {
array.add(newNode);//将这个新结点加入队列
arrayForUse.add(newNode);//将array中的元素复制到arrayForUse当中去
}
}
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
private static boolean ReadInstruc(JobsNode Work) {
//读取作业的用户程序指令
String txtPath = Main.inPath + Work.JobsID + ".txt";
try (
FileReader fileReader = new FileReader(txtPath);
BufferedReader bufferedReader = new BufferedReader(fileReader);
) {
String line;
String[] lines;//用于分割这个作业中的指令段编号、用户程序指令的类型、访问的逻辑地址
while ((line = bufferedReader.readLine()) != null) {
//扫描txt文件中的所有行
lines = line.split(",");//按照","进行分割
Instruction newInstruct = new Instruction(Integer.parseInt(lines[0]), Integer.parseInt(lines[1]), Integer.parseInt(lines[2]));
Work.Instrucs.add(newInstruct);
}
} catch (IOException e) {
e.printStackTrace();
return false;
}
//预留未找到指令报错
return true;
}
}
class JobsNode {
//作业结点的结构体
public static int RandomJobsID = 1001;
public int JobsID;//作业序号,从1001标注为随机实时新作业请求生成的作业序号
public int Priority;//作业优先级
public int InTimes;//作业请求时间
public int InstrucNum;//作业包含的程序指令数目
public int FinishInstrucNum = 0; //作业已完成的程序指令数目
public ArrayList<Instruction> Instrucs = new ArrayList<>();//作业包含的用户程序指令
public JobsNode() {
//作业结点的无参构造方法
}
public JobsNode(int priority, int inTime, int instrucNum, ArrayList<Instruction> instrucs) {
//作业结点的有参构造方法,用于随机实时新作业请求生成新的作业结点,并将其加入队列
this.JobsID = RandomJobsID;
RandomJobsID++;//预留给下一个结点的ID
this.Priority = priority;
this.InTimes = inTime;
this.InstrucNum = instrucNum;
this.Instrucs = instrucs;
JobsArray.array.add(this);//将这个新结点加入队列
JobsArray.arrayForUse.add(this);//将array中的元素复制到arrayForUse当中去
}
}
class Instruction {
//指令的结构体
public int Instruc_ID;//指令段编号
public int Instruc_State;//用户程序指令的类型
public int L_Address;//用户程序指令访问的逻辑地址(物理地址)
public int InRunTimes;//指令的运行时间
public int P_Address;//用户程序指令访问的页内地址
public int P; //页号
public int B; //块号
public int D; //页内地址
public Instruction(int id, int state) {
//Instruction指令类含有,id编号、state指令类型的构造方法
this.Instruc_ID = id;
this.Instruc_State = state;
//根据指令类型,设置指令的运行时间
switch (this.Instruc_State) {
case 0: {
this.InRunTimes = (int) ThreadDefine.time_Instruct0;
break;
}
case 1: {
this.InRunTimes = (int) ThreadDefine.time_Instruct1;
break;
}
case 2: {
this.InRunTimes = (int) ThreadDefine.time_Instruct2;
break;
}
case 3: {
this.InRunTimes = (int) ThreadDefine.time_Instruct3;
break;
}
case 4: {
this.InRunTimes = (int) ThreadDefine.time_Instruct4;
break;
}
case 5: {
this.InRunTimes = (int) ThreadDefine.time_Instruct5;
break;
}
}
}
public Instruction(int id, int state, int logicalAdd) {
//Instruction指令类含有,id编号、state指令类型、访问的逻辑地址的构造方法
this.Instruc_ID = id;
this.Instruc_State = state;
this.L_Address = logicalAdd;
String address = decimalToBinary(logicalAdd, 14);
this.B = Integer.parseInt(address.substring(0, 4));
this.D = Integer.parseInt(address.substring(4, 14));
//计算分页地址
this.P = this.B / 4;
address = decimalToBinary(P, 4) + address.substring(4, 14);
this.P_Address = Integer.parseInt(address, 2);
//根据指令类型,设置指令的运行时间
switch (this.Instruc_State) {
case 0: {
this.InRunTimes = (int) ThreadDefine.time_Instruct0;
break;
}
case 1: {
this.InRunTimes = (int) ThreadDefine.time_Instruct1;
break;
}
case 2: {
this.InRunTimes = (int) ThreadDefine.time_Instruct2;
break;
}
case 3: {
this.InRunTimes = (int) ThreadDefine.time_Instruct3;
break;
}
case 4: {
this.InRunTimes = (int) ThreadDefine.time_Instruct4;
break;
}
case 5: {
this.InRunTimes = (int) ThreadDefine.time_Instruct5;
break;
}
}
}
public Instruction() {
//Instruction指令类的无参构造方法
}
public static String decimalToBinary(int num, int size) { // 返回10进制转换的size位2进制逻辑地址
StringBuilder binStr = new StringBuilder();
for (int i = size - 1; i >= 0; i--) {
binStr.append(num >>> i & 1);
}
return binStr.toString();
}
}
Main
public class Main {
public static final String inPath = ".\\CODE\\input\\";//预设的作业请求txt文件的路径
public static final int timeSliceSize1 = 2;//就绪队列1的时间片大小
public static final int timeSliceSize2 = 4;//就绪队列2的时间片大小
public static final int timeSliceSize3 = 6;//就绪队列3的时间片大小
public static final CPU cpu0 = new CPU();
public static Memory memory0 = new Memory();
public static final GUI frame = new GUI();
public static final GUI_disk frame_disk = new GUI_disk();
public static void main(String[] arg0) {
System.out.println(System.getProperty("user.dir"));
GUI.Create(arg0);
while (true) {
if (!GUI.startFlag) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else
break;
}
if (!Init.Initialize(inPath + "19219212-jobs-input.txt"))//初始化,读取作业请求
{
System.out.println("Error:初始化失败,请检查.txt文件。");
System.exit(0);//退出程序的运行
}
// 每一秒钟发生一次时钟中断
ClockInterrupt clockInter = new ClockInterrupt(1.0);
NewWorkReq newWorkReq = new NewWorkReq(ThreadDefine.time_NewWorkReq);
InputBlock_thread bq1Schedule = new InputBlock_thread(ThreadDefine.time_Instruct2);
OutputBlock_thread bq2Schedule = new OutputBlock_thread(ThreadDefine.time_Instruct3);
BQ3Schedule bq3Schedule = new BQ3Schedule(ThreadDefine.time_Instruct4);
BQ4Schedule bq4Schedule = new BQ4Schedule(ThreadDefine.time_Instruct5);
BQ5Schedule bq5Schedule = new BQ5Schedule(ThreadDefine.time_Instruct6);
PageFaultInterrupt pageFaultSchedule = new PageFaultInterrupt();
clockInter.start();
newWorkReq.start();
bq1Schedule.start();
bq2Schedule.start();
bq3Schedule.start();
bq4Schedule.start();
bq5Schedule.start();
pageFaultSchedule.start();
}
}