操作系统实验java

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

操作系统实验

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();
    }
}
操作系统实验—进程调度算法(java 模拟进程调度的5个算法:FCFS、SJF、RR、PR(动态)、HRRN 阅读详情

相关推荐

操作系统实验——java银行家算法

课程设计题目:银行家算法 设计要求: (1)有录入界面动态录入进程数、资源种类数、各类资源总数、t0时刻各进程的最大需求数、已分配数等信息; (2)有算法选择界面,能够进行安全性检测、对进程动态请求资源的银行家算法检查、退出等的功能选择,要求可以进行多进程多次的资源请求; (3)有输出界面,要求能够输出安全性检测的结果、如安全能够输出安全序列、能够输出进程请求资源后是否分配的结果,若不能分配要输出...

zdd_8520的博客 706

操作系统管理---虚拟存储器-实验报告-代码(1).doc

操作系统管理---虚拟存储器-实验报告-代码(1).doc

JAVA操作系统实验存储管理图形化模拟程序

是一个模拟存储管理过程的操作系统程序,采用JAVA16编写,有图形化界面GUI。程序包含首次适应算法、循环首次适应算法、最佳算法和最差算法。并且包括存储收回的分区合并问题的四种情况。

操作系统实验

并发程序设计

weixin_51942493的博客 8087

计算机操作系统实验报告四则

计算机操作系统实验报告留档

m0_61126523的博客 2395

计算机操作系统实验

OS实验

qq_64270799的博客 2243

操作系统模拟进程调度实验报告java_操作系统实验2进程调度实验报告.doc

操作系统实验2进程调度实验报告佛山科学技术学院实 验 报 告课程名称 操作系统原理实验项目 实验二-进程调度实验讲义专业班级 姓 名 学 号指导教师 成 绩 日 期一、实验目的通过对进程调度算法的模拟,进一步理解进程的基本概念,加深对进程运行状态和进程调度过程、调度算法的理解。(1)掌握时间...

weixin_33176326的博客 2650

java实现首次适应算法 操作系统实验

因为操作系统实验需要,所以就花了点时间做了个首次适应算法的java实现 任务要求 编程实现首次适应算法。已知作业名、作业大小、作业提交时间、内存容量、碎片大小,要求使用分区大小不等的内存分区方法和首次适应分配算法给每次到来的作业分配内存。输出内存分区情况和分配情况。 首次适应算法(first fit): 空闲分区按地址递增的次序排列。在分配内存时,从链首开始顺序查找,直至找到一个大小能满足要求的空闲分区为止;如果分区大小-作业大小<=碎片,则直接分配,否则,按照作业的大小,从该分区中划出一块内存空间分

weixin_45942124的博客 2928

东北大学软件学院最新操作系统实验Java资源:助力操作系统学习

东北大学软件学院最新操作系统实验Java资源:助力操作系统学习 去发现同类优质开源项目:https://gitcode.com/ 在众多计算机科学领域中,操作系统无疑是基础且核心的组成部分。今天,我们要为大家介绍一个实用且高效的开源项目——东北大学软件学院最新操作系统实验Java资源。 项目介绍 本项目是一个专门为东北大学软件学院操作系统课程设计的Java代码库。它汇集了学长学姐们的经验与智慧,为...

gitblog_06715的博客 363

java文件管理实验_操作系统实验(文件目录管理java实现).doc

操作系统实验(文件目录管理java实现)操作系统实验(文件目录管理java实现)一 实验目的1 深刻理解文件目录管理的概念。2 掌握文件目录管理问题,文件系统的树形结构。二 实验设备PC机三 实验内容在Java开发平台模拟文件目录管理问题,文件系统的树形结构。四 程序的主要代码/**文件以@为结束标志,来区分文件与文件夹。创建文件或文件夹时,必须输入所在路径,否则默认创建在第一级。删除文件也必须...

weixin_36243867的博客 809

天津理工大学java上机实验报告实验四:java多线程技术_天津理工大学操作系统实验报告实验三...

天津理工大学操作系统实验报告实验实验报告学院(系)名称计算机与通信工程学院姓名学号专业计算机科学与技术班级2010级2班实验项目实验三磁盘调度算法的实现课程名称操作系统课程代码0668036实验时间2011 年12月24日 第3、4节2011 年12月27日 第7、8节2012 年12月30日 第7、8节实验地点软件实验室7-215批改意见成绩教师签字 实验内容1 本实验模拟操作系统的磁盘寻道...

weixin_35070578的博客 706

操作系统 实验一 多道程序、进程、分时系统模拟(java)

1) 利用程序设计语言模拟分时系统中多个进程按时间片轮转调度算法进行进程调度的过程; (2) 假设有五个进程A,B,C,D,E,它们的到达时间及要求服务的时间分别为: 进程名 A B C D E 到达时间 0 2 4 6 8 服务时间 3 6 4 5 2 时间片大小为1,利用程序模拟A,B,C,D,E五个进程按时间片轮转的调度及执行过程并计算周转时间及带权周转时间。

weixin_62278826的博客 1387

操作系统实验 Java

<br />作系统实验项目开发声明:<br />    1,本人是java初学者,菜鸟级别,发此贴谨以和其他java初学者交流经验,并希望有高手不吝赐教;<br />    2,本贴公分两期,第一期为项目的开发实验的完成,主要介绍本人在开发过程中的想法和实现过程;第二期为代码分析和项目评估,主要是通过对比本人作品和其他作者作品,浅谈这一次实验的感受和经验,进一步探究java项目开发流程和技术问题;<br />    3,第二期中会引用他人的代码,一些是由本人网上下载得来,另一些由同学传送,来源不甚详细,这

YZZZFHLC201314的专栏 3171

探索进程调度的奥秘:JAVA操作系统实验图形化模拟程序

探索进程调度的奥秘:JAVA操作系统实验图形化模拟程序 【下载地址】JAVA操作系统实验进程调度图形化模拟程序 本资源提供了一个用JAVA 16编写的操作系统实验程序,主要用于模拟进程调度过程,并提供图形化界面(GUI)。该程序实现了三种常见的进程调度算法:先进先出算法(FIFO)、短进程优先算法(SJF)和响应比高者优...

gitblog_09763的博客 655

Java模拟操作系统实验一:四种进程调度算法实现(FCFS,SJF,RR,HRN)

前言 刚学完操作系统模拟实现了其中一些经典的算法,内容比较多,打算写一个系列的总结,将自己的源码都分享出来,既方便自己以后复习,也希望能帮助到一些刚入坑的小伙伴。我的所有代码的运行环境都是基于Eclipse,jdk1.10下。 1.问题概述 编程实现常用调度算法,即先来先服务、短作业(进程)优先、时间片轮转以及最高响应比优先调度算法。编程语言及环境不限。须给出关键数据结构、算法以及变量的详...

走过,路过,别错过的博客 3万+

java实验多生产者消费者问题,操作系统实验(生产者消费者问题java实现).doc

操作系统实验(生产者消费者问题java实现)操作系统实验(生产者消费者问题java实现)一 实验目的1 深刻理解进程同步的概念。2 掌握经典同步问题,生产者——消费者问题。二 实验设备PC机三 实验内容在Java开发平台模拟经典进程同步问题,生产者——消费者问题。四 程序的主要代码import java.awt.*;import javax.swing.*;import java.awt.eve...

weixin_42443651的博客 564

动态分区分配(java) 操作系统实验

四种方法就不多介绍了,别的可以看,只是学生作品记录,做的地方还有许多不足 1.比如说当剩余空间Space的start = end相等时没有删除该剩余空间,反正是不想想了 2.还有的就是main方法只能理解过后才明白它在干什么,不能很清晰的设计程序步骤 3.ps:应付作业,我真可恶啊 package OS.Memory.T2; import java.util.*; public class Memory { public static void main(String[] args) {

skfenqizhe的博客 1093

java 银行家算法_操作系统实验——java银行家算法

实验2银行家算法(2学时)一、实验目的理解银行家算法,掌握进程安全性检查的方法及资源分配的方法。二、实验内容编写程序实现银行家算法,并验证程序的正确性。三、实验要求编制模拟银行家算法的程序,并以下面给出的例子验证所编写的程序的正确性。例子:某系统有A、B、C、D 4类资源共5个进程(P0、P1、P2、P3、P4)共享,各进程对资源的需求和分配情况如下表所示。进程已占资源最大需求数ABCDABCDP...

weixin_35144647的博客 922

实验模拟操作系统内存管理 java代码及解释_操作系统实验四(内存管理之固定分区分配)...

/*实验四-内存管理之固定分区分配算法思想:预先将内存空间划分成若干个空闲分区,分配过程根据用户需求将某一个满足条件的分区直接分配(不进行分割),作业完成后回收对应内存。整个分配过程分区大小和个数不发生变化。*/#include#include#includeusing namespacestd;#define getpch(type) (type*)malloc(sizeof(type))int...

weixin_33228847的博客 784
上一篇: 排队就餐管理方案设计C++
下一篇: 操作系统实验python
todcode
博客等级 码龄7年 359粉丝 108原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值