- 操作系统作业需要,续写一段C语言版的时间轮转法的进程调度模拟,我表示我不想、我不要、我不会。
- 所以我就重构了Java版的(但愿最终给过)
代码说明
- StreamUtils是工具类,用于序列化IO操作
- ProcStruct是进程类,这里大多是复制作业要求中的字段定义
- ProcessScheduling是运行类,包括主函数,各种方法,全局定义等
- 至于具体内容,个人认为注释写的还算比较详细~
- 如何运行?运行主函数即可。
package processScheduling;
import java.io.*;
import java.util.Arrays;
import java.util.List;
/**
* Created by CHEN on 2019/11/6.
*/
public class StreamUtils implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 序列化,List
*
* @param list
* @param file
* @param <T>
* @return
*/
public static <T> boolean writeObject(List<T> list, File file) {
T[] array = (T[]) list.toArray( );
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file))) {
out.writeObject(array);
out.flush( );
return true;
} catch (IOException e) {
e.printStackTrace( );
return false;
}
}
/**
* 反序列化,List
*
* @param file
* @param <E>
* @return
*/
public static <E> List<E> readObjectForList(File file) {
E[] object;
try (ObjectInputStream out = new ObjectInputStream(new FileInputStream(file))) {
object = (E[]) out.readObject( );
return Arrays.asList(object);
} catch (IOException e) {
e.printStackTrace( );
} catch (ClassNotFoundException e) {
e.printStackTrace( );
}
return null;
}
}
package processScheduling;
import java.io.Serializable;
import java.util.Arrays;
/**
* 进程结构
* Created by CHEN on 2019/11/5.
*/
public class ProcStruct implements Serializable,Comparable {
private Integer p_pid; // 进程的标识号
private char p_state; // 进程的状态,C--运行 R--就绪 W--组塞 B--后备 F--完成
private Integer[] p_rserial = new Integer[5]; // 模拟的进程执行的CPU和I/O时间数据序列,间隔存储,第0项存储随后序列的长度(项数),以便知晓啥时该进程执行结束
private Integer p_pos; // 当前进程运行到的位置,用来记忆执行到序列中的哪项
private Integer p_starttime; // 进程建立时间
private Integer p_endtime; // 进程运行结束时间
private Integer p_cputime; // 当前运行时间段进程剩余的需要运行时间
private Integer p_iotime; // 当前I/O时间段进程剩余的I/O时间
//初始化必须给值的量有:p_pid、p_state、p_rserial[]、p_pos=1、p_cputime()、p_endtime、
public ProcStruct(Integer p_pid,Integer[] p_rserial, Integer p_starttime){
this.p_pid = p_pid;
this.p_state = 'B';
this.p_rserial = p_rserial;
this.p_pos = 1;//开始是第一项未执行
this.p_cputime = p_rserial[1];//时间片统一给
this.p_starttime = p_starttime;//创建时间
}
public ProcStruct() {
}
public ProcStruct(Integer p_pid, char p_state, Integer[] p_rserial, Integer p_pos, Integer p_starttime, Integer p_endtime, Integer p_cputime, Integer p_iotime) {
this.p_pid = p_pid;
this.p_state = p_state;
this.p_rserial = p_rserial;
this.p_pos = p_pos;
this.p_starttime = p_starttime;
this.p_endtime = p_endtime;
this.p_cputime = p_cputime;
this.p_iotime = p_iotime;
}
public Integer getP_pid() {
return p_pid;
}
public void setP_pid(Integer p_pid) {
this.p_pid = p_pid;
}
public char getP_state() {
return p_state;
}
public void setP_state(char p_state) {
this.p_state = p_state;
}
public Integer[] getP_rserial() {
return p_rserial;
}
public void setP_rserial(Integer[] p_rserial) {
this.p_rserial = p_rserial;
}
public Integer getP_pos() {
return p_pos;
}
public void setP_pos(Integer p_pos) {
this.p_pos = p_pos;
}
public Integer getP_starttime() {
return p_starttime;
}
public void setP_starttime(Integer p_starttime) {
this.p_starttime = p_starttime;
}
public Integer getP_endtime() {
return p_endtime;
}
public void setP_endtime(Integer p_endtime) {
this.p_endtime = p_endtime;
}
public Integer getP_cputime() {
return p_cputime;
}
public void setP_cputime(Integer p_cputime) {
this.p_cputime = p_cputime;
}
public Integer getP_iotime() {
return p_iotime;
}
public void setP_iotime(Integer p_iotime) {
this.p_iotime = p_iotime;
}
@Override
public String toString() {
return "ProcStruct{" +
"p_pid=" + p_pid +
", p_state=" + p_state +
", p_rserial=" + Arrays.toString(p_rserial) +
", p_pos=" + p_pos +
", p_starttime=" + p_starttime +
", p_endtime=" + p_endtime +
", p_cputime=" + p_cputime +
", p_iotime=" + p_iotime +
'}';
}
// 用于list.sort
@Override
public int compareTo(Object o) {
if (o instanceof ProcStruct) {
ProcStruct procStruct = (ProcStruct) o;
//首先用starttime比较
int i = this.p_starttime.compareTo(procStruct.p_starttime);
if (i == 0) {
//当前io剩余时间为第二比较标准
return this.p_iotime.compareTo(procStruct.p_iotime);
}else {
return i;
}
}
return 0;
}
}
package processScheduling;
import java.io.File;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Random;
/**
* Created by CHEN on 2019/11/5.
*/
public class ProcessScheduling {
public static int ClockNumber; // 系统时钟
public static int ProcNumber; // 系统中模拟产生的进程总数
public static int FinishedProc; // 系统中目前已执行完毕的进程总数
public static ArrayList<ProcStruct> procStructs = new ArrayList<>( );//进程列表
public static LinkedList<ProcStruct> IOProc = new LinkedList<>( );//CPU运行、阻塞的进程
public static LinkedList<ProcStruct> CPUProc = new LinkedList<>( );//IO运行、阻塞的进程
public static LinkedList<ProcStruct> FinProc = new LinkedList<>( );//完成的进程
// 随机创建进程
public static void Create_ProcInfo() {
System.out.println("Create_ProcInfo.......");
Random random = new Random( );
Integer[] p_rserial;
ProcStruct procStruct;
// 创建至多10个进程
for (int i = ProcNumber; i < 10; i++) {
p_rserial = new Integer[4];
//产生随机数组
// [1-10)
p_rserial[0] = random.nextInt(3) + 1;
for (int j = 1; j <= p_rserial[0]; j++) {
// [1-5)
p_rserial[j] = random.nextInt(3) + 1;
}
// public ProcStruct(int p_pid,int[] p_rserial, int p_cputime)
//进程id:1-65535 p_rserial随机生成1-9秒的任务列表 starttime:1-10秒之间
procStruct = new ProcStruct(random.nextInt(65535)+1, p_rserial, random.nextInt(5) + 1);
procStructs.add(procStruct);
}
//更新ProcNumber
ProcNumber = procStructs.size( );
//显示
DisData( );
}
// 展示所创建的进程序列
public static void DisData() {
for (ProcStruct proc : procStructs
) {
System.out.println(proc);
}
//序列化保存
StreamUtils.writeObject(procStructs, new File("./prStructs.txt"));
}
// 进程调度函数
public static void Scheduler_FF() {
if (ProcNumber == 0) {
procStructs = new ArrayList<>( );
// 如果队列中没有进程则向文件中读取上次保存的进程
for (Object p : StreamUtils.readObjectForList(new File("./prStructs.txt"))
) {
procStructs.add((ProcStruct) p);
}
ProcNumber = procStructs.size( );
}
// //验证是否拿到
// for (ProcStruct p: procStructs
// ) {
// System.out.println(p );
// }
FinProc = new LinkedList<>( );
FinishedProc = 0;
//时钟初始化
ClockNumber = 0;
// 执行算法
while (FinishedProc < ProcNumber) {
ClockNumber++; // 时钟前进1个单位
NewReadyProc( ); // 判别新进程是否到达
Cpu_Sched( ); // CPU调度
IO_Sched( ); // IO调度
Display_ProcInfo( ); //显示当前状态
// 睡眠0.7s
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace( );
}
}
Cal();
//清空当前队列,要上次的内容去.class文件中找出数据重新运行一遍
procStructs.clear( );
ProcNumber = 0;
}
// 判断当前是否有新进程到达
public static void NewReadyProc() {
for (ProcStruct p : procStructs
) {
if (p.getP_starttime( ) == ClockNumber) {
// 进程的状态,C--运行 R--就绪 W--组塞 B--后备 F--完成
if (CPUProc.size( ) == 0) {
p.setP_state('R');
}
else {
p.setP_state('W');
}
// 如果有加到CPU队列末尾(默认~CPU先)
CPUProc.add(p);
}
}
}
// CPU调度模拟, 每次只执行一个CPU时间片p=1
public static void Cpu_Sched() {
if (CPUProc.size( ) != 0) {
// 弹出一个
ProcStruct procStruct = CPUProc.pop( );
//变为运行状态
State_Change(0, procStruct);
if (procStruct.getP_state( ) == 'C') {
procStruct.setP_cputime(procStruct.getP_cputime( ) - 1);
//如果cup运行时间耗尽
if (procStruct.getP_cputime( ) == 0) {
//且进程进度已经到了最后,进程完成,加入完成队列
if (procStruct.getP_pos( ).equals(procStruct.getP_rserial( )[0])) {
// 进程结束,进入结束队列(为了好收集)
Proc_Finish(procStruct);
} else if (procStruct.getP_pos( ) < procStruct.getP_rserial( )[0]) {
//进度未到最后,进程进度+1
procStruct.setP_pos(procStruct.getP_pos( ) + 1);
//IO剩余时间赋值
procStruct.setP_iotime(procStruct.getP_rserial( )[procStruct.getP_pos( )]);
//加到IO队列尾 12
procStruct = State_Change(1, procStruct);
IOProc.add(procStruct);
}
} else if (procStruct.getP_cputime( ) > 0) {
//放回CPU队尾 11
procStruct = State_Change(1, procStruct);
CPUProc.add(procStruct);
}
Head_State_Change(0);
} else {
CPUProc.add(procStruct);
}
}
}
// I/O调度模拟, 与CPU调度操作类似。排在队首的进程得到一个时间片服务
public static void IO_Sched() {
if (IOProc.size( ) != 0) {
// 弹出一个
ProcStruct procStruct = IOProc.pop( );
procStruct = State_Change(0, procStruct);
if (procStruct.getP_state( ) == 'C') {
procStruct.setP_iotime(procStruct.getP_iotime( ) - 1);
//如果cup运行时间耗尽
if (procStruct.getP_iotime( ) == 0) {
//且进程进度已经到了最后,进程完成,加入完成队列
if (procStruct.getP_pos( ).equals(procStruct.getP_rserial( )[0])) {
Proc_Finish(procStruct);
} else if (procStruct.getP_pos( ) < procStruct.getP_rserial( )[0]) {
//进度未到最后,进程进度+1
procStruct.setP_pos(procStruct.getP_pos( ) + 1);
//CPU剩余时间赋值
procStruct.setP_cputime(procStruct.getP_rserial( )[procStruct.getP_pos( )]);
//加到CPU队列尾 21
procStruct = State_Change(1, procStruct);
CPUProc.add(procStruct);
// 如果CPU队列只有刚转进去的元素,则其状态立马变为R
if (CPUProc.size( ) == 1) {
Head_State_Change(0);
}
}
} else if (procStruct.getP_iotime( ) > 0) {
//IO->IO 22
procStruct = State_Change(1, procStruct);
IOProc.add(procStruct);
}
Head_State_Change(1);
} else {
IOProc.add(procStruct);
}
}
}
// 显示系统当前状态,每秒运行完毕之后都显示一次
public static void Display_ProcInfo() {
//显示:CPU队列?IO队列?阻塞状态?非阻塞状态?
System.out.println("\n当第:" + ClockNumber+"秒运行完毕之后");
System.out.println("CPUProc:");
for (ProcStruct p : CPUProc
) {
System.out.println(p);
}
System.out.println("IOProc:");
for (ProcStruct p : IOProc
) {
System.out.println(p);
}
System.out.println("FinProc:");
for (ProcStruct p : FinProc
) {
System.out.println(p);
}
}
// 元素的状态转换
public static ProcStruct State_Change(int type, ProcStruct procStruct) {
//type: 1=做完一次CPU/IO之后的元素的转换 0=做之前的转换,或者下次头元素的状态转换
if (type == 1) {
procStruct.setP_state('W');
} else if (type == 0) {
if (procStruct.getP_state( ) == 'W') {
procStruct.setP_state('R');
} else if (procStruct.getP_state( ) == 'R') {
procStruct.setP_state('C');
}
}
return procStruct;
}
// CPU与IO:队列的第一个进程的状态转换
public static void Head_State_Change(int type) {
//type: 0=CPU队列头部元素状态的转换,1代表的是IO队列头部元素状态的转换
if (type == 0) {
if (CPUProc.size( ) >= 1) {
//这段是把下一个进程标记为R
ProcStruct procStruct = CPUProc.pop( );
State_Change(0, procStruct);
CPUProc.addFirst(procStruct);
}
} else if (type == 1) {
if (IOProc.size( ) >= 1) {
//这段是把下一个进程标记为R
ProcStruct procStruct = IOProc.pop( );
State_Change(0, procStruct);
IOProc.addFirst(procStruct);
}
}
}
// 将运行完毕的进程加入结束队列,以便于显示,非系统调度内容
public static void Proc_Finish(ProcStruct procStruct) {
procStruct.setP_state('F');
procStruct.setP_endtime(ClockNumber);
FinProc.add(procStruct);
FinishedProc = FinProc.size( );
}
// 计算周转时间,带权周转时间
public static void Cal(){
System.out.println("\n周转/带权周转时间为:");
for (ProcStruct p:FinProc
) {
int total_time=p.getP_endtime()-p.getP_starttime();
int service_time =0;
for (int i=1;i<=p.getP_rserial()[0];i++){
service_time+=p.getP_rserial()[i];
}
System.out.println("ID:"+p.getP_pid()+"\t周转时间:"+total_time+"\t带权周转时间:"+(total_time*1.0/service_time));
}
}
public static void main(String[] args) {
//初始化
char ch;
ClockNumber = 0; // 系统时钟
ProcNumber = 0; // 当前系统中的进程总数
FinishedProc = 0;
while (true) {
System.out.println("***********************************");
System.out.println(" 1: 建立进程调度数据序列 ");
System.out.println(" 2: 读进程信息,执行调度算法");
System.out.println(" 3: 退出");
System.out.println("***********************************");
System.out.println("Enter your choice (1 ~ 3): ");
try {
ch = (char) System.in.read( ); //如果输入信息不正确,继续输入
if (ch == '2') Scheduler_FF( ); // 选择2
else if (ch == '1') Create_ProcInfo( ); // 选择1
else if (ch == '3') System.exit(0); // 选择3
else System.out.println("Error input......");//错误输入
ch = (char) System.in.read( );
} catch (Exception e) {
e.printStackTrace( );
}
}
}
}