进程管理系统的设计与实现
要求:
(1)设计一个完整的进程调度系统,至少包含三种常用的算法(FCFS、SPF、静态优先权、响应比、时间片轮转),系统中至少包含5个进程,并且能够体现进程的动态申请;
(2)定义PCB;
(3)结果要能够显示出进程的调度序列及进入系统的时间、运行时间、完成时间、周转时间、带权周转时间、优先权等必要信息;
(4〉设计的输入数据要能体现算法的思想
本人使用Java语言编写,编写过程中在网络中查找大量资料。
本人是本篇代码的唯一作者。
本代码仅限参考学习,禁止抄袭!
各算法介绍:
先来先服务算法First Come First Service(FCFS):
FCFS的意思是先来先服务(First Come First Service)。
顾名思义就是按照进程被添加到等待队列的先后顺序来进行调用的。
短进程优先算法Short Process First(SPF):SPF的意思是短进程优先(Short Process First),服务时间短的进程在就绪队列前面。
静态优先级调度算法Static Priority-scheduling algorithm(SPSA):系统在调度进程时按优先级从高到低进行调度,在进程运行过程中优先级不再动态地改变。
高响应比优先调度算法Highest Response Ratio Next(HRRN):响应比 =(等待时间+要求服务时间)/ 要求服务时间
为每一个作业引入一个动态优先级,即优先级是可以改变的。
它随等待时间延长而增加,这将使长作业的优先级在等待期间不断地增加,
等到足够的时间后,必然有机会获得处理机。
时间片轮转算法Round Robin(RR):系统把所有就绪进程按先来先服务规则排成一个队列,就绪队列中的所有进程,
可以依次轮流获得一个时间片的处理时间,然后系统又回到队列的开始部分,如此不断循环。
代码部分:
Main:
package osProject.sjs;
import java.io.*;
import java.util.*;
public class Main
{
static int num;//进程数目
static PCB[] arr = new PCB[100];
static PCB[] arrUse = new PCB[100];
static Scanner sc = new Scanner(System.in);
public static void main(String[] args)
{
System.out.println("欢迎进入进程管理系统,请按照提示输入进程信息。");
Main M = new Main();
M.inputProcessInf(M);//输入进程,选择输入进程的方式
M.displayProcessInf();//展示进程初始信息
//进入菜单选择功能,可以使用多个算法调度进程
while(true)
{//此while为了多次选择功能i,在选择退出功能时置flag=1,然后退出
//本程序使用arrUse而保留arr原数据,为了每次进入不同算法时不存在其他算法的遗留结果数据
M.copyArray();//将arr中的数据内容拷贝到arrUse中,令算法使用arrUse中未被赋值过的干净数据
int flag = 0;//用来标记是否需要退出选择算法,置1则退出算法
M.displayMenu();//展示系统菜单,每执行完一次功能i,再次选择功能时展示一次
while(true)
{//为了防止输入i的错误导致无法选择功能,此while直到正确选择功能i时退出,每个if的最后都要有break
try
{//在try语句块中书写可能发生异常的代码(选择功能),增强程序健壮性
int i = sc.nextInt();
if(i == 1)
{//选择先来先服务算法FCFS
executeFCFS();//执行FCFS算法
break;
}
else if(i == 2)
{//选择短进程优先算法SPF
executeSPF();//执行SPF算法
break;
}
else if(i == 3)
{//选择静态优先级调度算法SPSA
executeSPSA();//执行SPSA算法
break;
}
else if(i == 4)
{//选择高响应比优先调度算法HRRN
executeHRRN();//执行HRRN算法
break;
}
else if(i == 5)
{//时间片轮转算法RR
executeRR();//执行RR算法
break;
}
else if(i == 6)
{//选择退出系统
flag = 1;//flag置1,表示需要退出系统
break;
}
else
{//输入i不是要求的选项,提示重新选择
System.out.println("输入有误,请重新输入:");//提示功能i选择的错误
//输入错误时不需要break,需要重新输入
}
}
catch(Exception e)
{
System.out.println("您输入的不是数字,请重新输入!");
sc = new Scanner(System.in);//这一句要加,否则会进入死循环
}
}
if(flag == 1)
{//当flag置1时,退出系统
break;
}
}
sc.close();
}
private static void executeRR()
{//执行RR算法
RR rr = new RR(num, arrUse, sc);//RR算法需要输入时间片大小,所以需要传入Scanner对象
rr.run();
System.out.println("请选择是否将本次算法执行结果存入文件?");
System.out.println("1.是\t 2.否");
while(true)
{//while死循环是为了防止输入错误时令用户再次输入,否则输入错误后就跳出了,没法选择存文件
int x = sc.nextInt();
if(x == 1 || x == 2)
{
if(x == 1) rr.writeFile();//将类数组写入文件
break;//当选择完文件操作后应该退出本层while
}
else
{
System.out.println("输入有误,请重新输入:");//提示文件操作的选择错误
sc = new Scanner(System.in);
//未选择完文件操纵,不需要退出本层while
}
}
}
private static void executeHRRN()
{//执行HRRN算法
HRRN hrrn = new HRRN(num, arrUse);
hrrn.run();
System.out.println("请选择是否将本次算法执行结果存入文件?");
System.out.println("1.是\t 2.否");
while(true)
{//while死循环是为了防止输入错误时令用户再次输入,否则输入错误后就跳出了,没法选择存文件
int x = sc.nextInt();
if(x == 1 || x == 2)
{
if(x == 1) hrrn.writeFile();//将类数组写入文件
break;//当选择完文件操作后应该退出本层while
}
else
{
System.out.println("输入有误,请重新输入:");//提示文件操作的选择错误
sc = new Scanner(System.in);
//未选择完文件操纵,不需要退出本层while
}
}
}
private static void executeSPSA()
{//执行SPSA算法
SPSA spsa = new SPSA(num, arrUse, sc);//SPSA算法要另外输入优先级,需要Scanner变量(也有其他方法)
spsa.run();
System.out.println("请选择是否将本次算法执行结果存入文件?");
System.out.println("1.是\t 2.否");
while(true)
{//while死循环是为了防止输入错误时令用户再次输入,否则输入错误后就跳出了,没法选择存文件
int x = sc.nextInt();
if(x == 1 || x == 2)
{
if(x == 1) spsa.writeFile();//将类数组写入文件
break;//当选择完文件操作后应该退出本层while
}
else
{
System.out.println("输入有误,请重新输入:");//提示文件操作的选择错误
sc = new Scanner(System.in);
//未选择完文件操纵,不需要退出本层while
}
}
}
private static void executeSPF()
{//执行SPF算法
SPF spf = new SPF(num, arrUse);
spf.run();
System.out.println("请选择是否将本次算法执行结果存入文件?");
System.out.println("1.是\t 2.否");
while(true)
{//while死循环是为了防止输入错误时令用户再次输入,否则输入错误后就跳出了,没法选择存文件
int x = sc.nextInt();
if(x == 1 || x == 2)
{
if(x == 1) spf.writeFile();//将类数组写入文件
break;//当选择完文件操作后应该退出本层while
}
else
{
System.out.println("输入有误,请重新输入:");//提示文件操作的选择错误
sc = new Scanner(System.in);
//未选择完文件操纵,不需要退出本层while
}
}
}
private static void executeFCFS()
{//执行FCFS算法
FCFS fcfs = new FCFS(num, arrUse);
fcfs.run();
System.out.println("请选择是否将本次算法执行结果存入文件?");
System.out.println("1.是\t 2.否");
while(true)
{//此while为了防止输入错误时令用户再次输入,否则输入错误后就跳出了,
//没法选择存文件,此while在选择文件操作完成后退出
int x = sc.nextInt();
if(x == 1 || x == 2)
{
if(x == 1) fcfs.writeFile();//将类数组写入文件
break;//当选择完文件操作后应该退出本层while
}
else
{
System.out.println("输入有误,请重新输入:");
sc = new Scanner(System.in);
//未选择完文件操纵,不需要退出本层while
}
}
}
private void displayMenu()
{
System.out.println("功能菜单:");
System.out.println("***********************************");
System.out.println("* 1.先来先服务算法 *");
System.out.println("* 2.短进程优先算法 *");
System.out.println("* 3.静态优先级算法 *");
System.out.println("* 4.高响应比优先调度算法 *");
System.out.println("* 5.时间片轮转算法 *");
System.out.println("* 6.退出系统 *");
System.out.println("***********************************");
System.out.println("请选择要执行的操作:");
}
private void copyArray()
{//将arr中的数据内容拷贝到arrUse中,使用arrUse而保留arr中的原始数据
//不能使用对象直接赋值,那样它们会引用同一块内容,两者会不独立
for(int i = 0; i < num; i++)
{
arrUse[i] = new PCB();
arrUse[i].setId(arr[i].getId());
arrUse[i].setName(arr[i].getName());
arrUse[i].setArriveTime(arr[i].getArriveTime());
arrUse[i].setServiceTime(arr[i].getServiceTime());
arrUse[i].setVisited(0);
}
}
private void displayProcessInf()
{//展示进程未执行算法时的初始信息
System.out.println("进程初始信息如下:");
for(int i = 0; i < num; i++)
{
//使用式样化输出函数printf()输出信息,使信息便于观看
//左对齐加"-","8"指域宽为8,占8个字符字符串用"s",整型用"d",浮点类型用"f"
System.out.printf("%-8s \t%-8s \t%-8s \t%-8s\n",
"进程id", "进程名", "到达时间", "服务时间");
System.out.printf("%-8d \t%-8s \t%-8d \t%-8d\n",
arr[i].getId(), arr[i].getName(), arr[i].getArriveTime(), arr[i].getServiceTime());
}
System.out.println();
}
private void fileReadProcess()
{//从文件中读入进程信息
File file = new File("processInf.dat");
try
{
FileInputStream fin = new FileInputStream(file);
ObjectInputStream in = new ObjectInputStream(fin);
num = fin.read();
for(int i = 0; i < num; i++)
{
arr[i] = (PCB)in.readObject();
}
in.close();
fin.close();
}
catch(Exception e)
{
System.out.println("文件\"processInf.dat\"不存在!请重新选择:");
return;//若文件不存在需要直接return,否则会输出下方“已读入完成”的语句
}
System.out.println("文件\"processInf.dat\"中的算法数据已读入完成。");
System.out.println();
}
private void fileWriteProcess()
{//将进程块信息写入文件中
File file = new File("processInf.dat");
try
{
FileOutputStream fout = new FileOutputStream(file);
ObjectOutputStream out = new ObjectOutputStream(fout);
fout.write(num);
for(int i = 0; i < num; i++)
{
out.writeObject(arr[i]);
}
out.close();
fout.close();
}
catch(Exception e)
{
e.printStackTrace();
}
System.out.println("本次算法执行结果已存入文件\"processInf.dat\"中。");
System.out.println();
}
private void readProcess()
{//从控制台手动输入进程信息
while(true)
{
try
{//在try语句块中书写可能发生异常的代码,增强程序健壮性
System.out.println("请输入进程数目(2-99):");
num = sc.nextInt();
if(num < 2 || num > 99)
{
System.out.println("您输入的数字不在要求范围内,请重新输入!");
}
else
{
System.out.println("进程数目为:" + num);
System.out.println("请按照提示输入进程相关信息。");
for(int i = 0; i < num; i++)
{
arr[i] = new PCB();
arr[i].setId(i+1);
System.out.println("第" + (i+1) + "个进程名:");
arr[i].setName(sc.next());
System.out.println("进程到达时间:");
arr[i].setArriveTime(sc.nextInt());
System.out.println("进程服务时间:");
arr[i].setServiceTime(sc.nextInt());
arr[i].setVisited(0);//置进程i未被执行过
}
break;//输入完毕,此处记得要break,否则会死循环
}
}
catch(Exception e)
{
System.out.println("您输入的不是数字,请重新输入!");
sc = new Scanner(System.in);//这一句要加,否则会进入死循环
}
}
System.out.println("进程信息输入完成!");
}
private void inputProcessInf(Main M)
{//输入进程,选择输入进程的方式
System.out.println("请选择输入进程方式:");
System.out.println("1.手动输入\t 2.文件读入");
while(true)
{//为了防止输入x的错误导致无法选择功能,此while直到正确选择功能x时退出,每个if的最后都要有break
int x = sc.nextInt();
if(x == 1)
{
M.readProcess();//从控制台读入用户输入的进程块信息,读入一次进程信息,可以使用多个算法计算
System.out.println("是否需要将进程信息保存到文件中?");
System.out.println("1.是\t 2.否");
while(true)
{//此while为了防止输入错误时令用户再次输入
int y = sc.nextInt();
if(y == 1 || y == 2)
{
if(y == 1) M.fileWriteProcess();//将程序中的进程块信息写入文件中
break;//当写入操作完成后,退出while循环
}
else
{
System.out.println("输入有误,请重新输入:");
sc = new Scanner(System.in);
//未正确选择操作,不需要退出本层while
}
}
break;
}
else if(x == 2)
{
M.fileReadProcess();//从文件读入进程块信息
break;
}
else
{
System.out.println("输入有误,请重新输入:");
sc = new Scanner(System.in);
//else中不用break,因为没有正确选择功能,需要在while中再次输入
}
}
}
}
PCB(进程控制块):
package osProject.sjs;
import java.io.*;
public class PCB implements Serializable
{
/**
*
*/
private static final long serialVersionUID = 1L;
private int id;//进程id
private String name;//进程名称
private int arriveTime;//进程进入系统的时间(未开始服务),进程到达时间
private int serviceTime;//进程服务时间,进程服务时间,需提前给出
private int alreadyServiceTime;//已经服务的时间,进程执行时记录
private int startTime;//进程服务开始时间
private int endTime;//进程服务完成时间
private int turnaroundTime;//周转时间,作业完成时间 - 作业到达时间
private double turnaroundTimeWithRight;//带权周转时间,周转时间 /服务时间
private int priority;//优先级
private double responseRatio;//HRRN中的响应比
private int visited;//是否被执行过,置0为未被执行过,置1为被执行过
PCB(){}//构造函数
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getArriveTime() {
return arriveTime;
}
public void setArriveTime(int arriveTime) {
this.arriveTime = arriveTime;
}
public int getServiceTime() {
return serviceTime;
}
public void setServiceTime(int serviceTime) {
this.serviceTime = serviceTime;
}
public int getAlreadyServiceTime() {
return alreadyServiceTime;
}
public void setAlreadyServiceTime(int alreadyServiceTime) {
this.alreadyServiceTime = alreadyServiceTime;
}
public int getStartTime() {
return startTime;
}
public void setStartTime(int startTime) {
this.startTime = startTime;
}
public int getEndTime() {