代码编织梦想

操作系统实验

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();
    }
}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/todcode/article/details/128750201

哈工大操作系统实验环境安装_学不完了ccccc的博客-爱代码爱编程

vmwarte上安装Ubuntu 20.04版本 具体安装步骤网上都能搜的到 这里给出百度网盘链接 链接:https://pan.baidu.com/s/1WOncZnIMtSGiDfCBbUkkwA 提取码:2crc

java基础学习 day34(stringbuilder,链式编程)-爱代码爱编程

1. StringBuilder概述 StringBuilder可以看作是一个容器,创建之后里面的内容是可变的作用:提高字符串的操作效率 例如: String s1 = “aaa”; String s2 = “bbb”;

在线教育-谷粒学院学习笔记(六)-爱代码爱编程

文章目录 1 内容介绍2 课程大纲列表后端实现3 课程大纲列表前端实现4 修改课程基本信息5 课程章节操作6 课程小节操作7 课程信息确认8 课程最终发布 1 内容介绍 课程大纲管理 课程大纲列表显

java总结(运算符)-爱代码爱编程

1.算数运算符 short s1=2; s1=s1+2; (编译不能运行) short s1=2; s1 +=2 ; (编译能运行,+=不改变变量本身的数据类型)

java 9 新特性 – 增强流 ( stream ) api-爱代码爱编程

Java 中引入了流 ( Stream ) 的概念,真的是大大方便了我们 java 程序员,我们可以使用流从一系列对象中执行聚合操作。 其实,Java 8 中的流已经很强大了,而且只要涉及到 IO,只要涉及到对一系列数据进行操作,几乎都有流的影子。 当然了,Java 9 还不忘对其继续增强,这次的改进主要是如何设置停止流的条件上。为此在流的实例上提供了

spring | sm整合(spring+mybatis)-爱代码爱编程

0️⃣使用工具 编辑器:IDEA企业版 构建系统:Maven 数据库:MySQL 1️⃣创建项目 🎏创建maven项目 选择新建项目,在E盘下创建名为SMDemo的项目,构建系统选择Maven. 🎏项目结构 src/main/java -

【183】java8对图片做顺时针旋转90度、逆时针旋转90度、旋转180度、水平翻转、垂直翻转操作。-爱代码爱编程

图片可以看作是矩阵。对图片的操作就是对矩阵的操作。下面按照不同操作分别进行讲解。 顺时针旋转90度 把原图片的最后一行,转变为新图片的第1列. 把原图片的倒数第2行,转变为新图片的第2列. …… 以此类推,进行变换。