文章目录
作业调度算法的简单实现(Java)
写在前面
前些天操作系统老师带着我们做了作业调度算法的实验,但是那份代码不是我这种菜鸟所能看得懂得,所以我打算自己用Java去实现这个实验,没有数据结构没有算法,仅仅是简单的逻辑。直接上代码,需要的直接copy
流程图
代码部分
项目结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gcKgW8DF-1621940033657)(image-20210525141704340.png)]
Process(要操作的对象)
package cn.作业调度;
import java.util.Objects;
/**
* 模拟进程的进程管理对象
*/
public class Process {
//定义成员变量
private String jobName; //作业名
private String status;//状态
private Float timeOfArrival;//到达时间
private Float serviceHours; //服务时间
//前三个变量是需要我们自己传入的,后面是用过计算得到的
private Float startExecutionTime;//开始执行时间
private Float completeTime; //完成时间
private Float turnaroundTime; //周转时间
private Float weightedTurnaroundTime;//带权周转时间
private Float writTime;//等待时间
//构造函数
//空参
public Process() {
}
//全参
public Process(String jobName, String status, Float timeOfArrival, Float serviceHours, Float startExecutionTime, Float completeTime, Float turnaroundTime, Float weightedTurnaroundTime, Float writTime) {
this.jobName = jobName;
this.status = status;
this.timeOfArrival = timeOfArrival;
this.serviceHours = serviceHours;
this.startExecutionTime = startExecutionTime;
this.completeTime = completeTime;
this.turnaroundTime = turnaroundTime;
this.weightedTurnaroundTime = weightedTurnaroundTime;
this.writTime = writTime;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getJobName() {
return jobName;
}
public void setJobName(String jobName) {
this.jobName = jobName;
}
public Float getTimeOfArrival() {
return timeOfArrival;
}
public void setTimeOfArrival(Float timeOfArrival) {
this.timeOfArrival = timeOfArrival;
}
public Float getServiceHours() {
return serviceHours;
}
public void setServiceHours(Float serviceHours) {
this.serviceHours = serviceHours;
}
public Float getStartExecutionTime() {
return startExecutionTime;
}
public void setStartExecutionTime(Float startExecutionTime) {
this.startExecutionTime = startExecutionTime;
}
public Float getCompleteTime() {
return completeTime;
}
public void setCompleteTime(Float completeTime) {
this.completeTime = completeTime;
}
public Float getTurnaroundTime() {
return turnaroundTime;
}
public void setTurnaroundTime(Float turnaroundTime) {
this.turnaroundTime = turnaroundTime;
}
public Float getWeightedTurnaroundTime() {
return weightedTurnaroundTime;
}
public void setWeightedTurnaroundTime(Float weightedTurnaroundTime) {
this.weightedTurnaroundTime = weightedTurnaroundTime;
}
public Float getWritTime() {
return writTime;
}
public void setWritTime(Float writTime) {
this.writTime = writTime;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Process process = (Process) o;
return Objects.equals(jobName, process.jobName) && Objects.equals(status, process.status) && Objects.equals(timeOfArrival, process.timeOfArrival) && Objects.equals(serviceHours, process.serviceHours) && Objects.equals(startExecutionTime, process.startExecutionTime) && Objects.equals(completeTime, process.completeTime) && Objects.equals(turnaroundTime, process.turnaroundTime) && Objects.equals(weightedTurnaroundTime, process.weightedTurnaroundTime) && Objects.equals(writTime, process.writTime);
}
@Override
public int hashCode() {
return Objects.hash(jobName, status, timeOfArrival, serviceHours, startExecutionTime, completeTime, turnaroundTime, weightedTurnaroundTime, writTime);
}
@Override
public String toString() {
return "Process{" +
"jobName='" + jobName + '\'' +
", status='" + status + '\'' +
", timeOfArrival=" + timeOfArrival +
", serviceHours=" + serviceHours +
", startExecutionTime=" + startExecutionTime +
", completeTime=" + completeTime +
", turnaroundTime=" + turnaroundTime +
", weightedTurnaroundTime=" + weightedTurnaroundTime +
", writTime=" + writTime +
'}';
}
}
FCFS算法实现
package cn.作业调度;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* 进程管理对象的实现类
*/
public class FCFS算法实现 {
private static List<Process> processList = new ArrayList<>(); //进程队列
private static Float time; //系统处理线程的总耗时
private static float averageTurnaroundTime; //平均周转时间
private static float averageWaitingTime;//平均等待时间
private static float averageWeightedTurnaroundTime;//平均带权周转时间
//函数运行的主函数
public static void main(String[] args) {
init();
input();
List<Process> list = FSFC();
for (Process process: list) {
System.out.println("进程名:"+process.getJobName()+
",到达时间:"+process.getTimeOfArrival()+
",运行时间:"+process.getServiceHours()+
",开始执行时间:" + process.getStartExecutionTime()+
",完成时间:"+process.getCompleteTime()+
",周转时间:"+process.getTurnaroundTime()+
",带权周转时时间:"+process.getWeightedTurnaroundTime()+
",等待时间:"+process.getWritTime());
}
calculateTheAverage(list);
System.out.println("处理总时间为:"+time+
",平均周转时间:"+averageTurnaroundTime+
",平均带权周转时间:"+averageWaitingTime+
",平均等待时间:"+averageWeightedTurnaroundTime);
}
/**
* 初始化链表
*/
public static void init(){
System.out.println("请输入要处理的线程数");
Scanner scanner = new Scanner(System.in);
int length = scanner.nextInt();
for(int i =0 ;i<length;i++){
processList.add(new Process());
}
}
/**
* 输入线程名和到达时间和服务时间
*/
public static void input(){
for (int i =0;i<processList.size();i++){
Process process = processList.get(i);
System.out.println("请输入第"+(i+1)+"个线程名:");
Scanner scanner = new Scanner(System.in);
process.setJobName(scanner.next());
System.out.println("请输入第"+(i+1)+"个线程的到达时间:");
process.setTimeOfArrival(scanner.nextFloat());
System.out.println("请输入第"+(i+1)+"个线程的服务时间");
process.setServiceHours(scanner.nextFloat());
}
}
/**
* 发现集合中的最小值,并返回其对应的下标
* @return
*/
public static int findMin(){
//获得第一个进程的到达时间
float min = processList.get(0).getTimeOfArrival();
for (int i =0 ;i<processList.size();i++){
if(min > processList.get(i).getTimeOfArrival()){
min = processList.get(i).getTimeOfArrival();
}
}
for(int i = 0;i<processList.size();i++){
if(min == processList.get(i).getTimeOfArrival()){
return i;
}
}
return -1;
}
public static List<Process> FSFC(){
List<Process> completionQueue = new ArrayList<>();//完成队列
int index = 0;
while (processList.size() != 0){
//发现集合中的进程到达时间最小的下标
index = findMin();
//判断进程处理总时间是否为空,为空说明PCB刚刚开始
//获得对应下标的对象
Process process = processList.get(index);
if(time == null){ //系统开始为第一个进程服务
//第一个进程,开始执行时间 = 进程到达时间
process.setStartExecutionTime(process.getTimeOfArrival()); //计算开始执行时间
//完成时间 = 开始执行时间 + 服务时间
process.setCompleteTime(process.getStartExecutionTime()+process.getServiceHours());
//周转时间 = 完成时间 - 达到时间
process.setTurnaroundTime(process.getCompleteTime() - process.getTimeOfArrival());
//带权周转时间 = 周转时间 / 运行时间(服务时间)
process.setWeightedTurnaroundTime(process.getTurnaroundTime() / process.getServiceHours());
//等待时间 = 周转时间 - 运行时间
process.setWritTime(process.getTurnaroundTime() - process.getServiceHours());
//此时系统时间 = 该进程的完成时间
time = process.getCompleteTime();
}else {
//如果前一个完成时间 ,小于到达时间,系统有空闲
if(time < process.getTimeOfArrival()){
float idle = process.getTimeOfArrival() - time;//空闲出来的时间
time += idle;
}
//排除第一个进程 开始执行时间 = 系统时间
process.setStartExecutionTime(time);
//完成时间 = 开始执行时间 + 服务时间(运行时间)
process.setCompleteTime(process.getStartExecutionTime() + process.getServiceHours());
//周转时间 = 完成时间 - 到达时间
process.setTurnaroundTime(process.getCompleteTime() - process.getTimeOfArrival());
//带权周转时间 = 周转时间 / 运行时间(服务时间)
process.setWeightedTurnaroundTime(process.getTurnaroundTime() / process.getServiceHours());
//等待时间 = 周转时间 - 运行时间
process.setWritTime(process.getTurnaroundTime() - process.getServiceHours());
//修正系统时间 此时系统时间 = 原来系统时间 + 此进程的完成时间(服务时间)
time += process.getServiceHours();
}
//将处理完成的进程添加到完成队列中
completionQueue.add(process);
//将进程移出原先队列
processList.remove(index);
}
return completionQueue;
}
/**
* 根据传入的集合
* 计算平均周转时间、平均带权周转时间、平均等待时间
*/
public static void calculateTheAverage(List<Process> processList){
float turnaroundTime = 0;//总周转时间
float weightedTurnaroundTime = 0;//总带权周转时间
float waitingTime = 0;//总等待时间
for (Process process: processList) {
turnaroundTime += process.getTurnaroundTime();
weightedTurnaroundTime += process.getWeightedTurnaroundTime();
waitingTime += process.getWritTime();
}
averageTurnaroundTime = turnaroundTime / processList.size();
averageWaitingTime = waitingTime / processList.size();
averageWeightedTurnaroundTime = weightedTurnaroundTime / processList.size();
}//计算平均
}
SJF算法实现
package cn.作业调度;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* SJF非抢占式调度算法
*/
public class SJF算法实现 {
private static List<Process> processList = new ArrayList<>(); //创建进程队列
private static Float time; //系统处理线程的总耗时
private static float averageTurnaroundTime; //平均周转时间
private static float averageWaitingTime;//平均等待时间
private static float averageWeightedTurnaroundTime;//平均带权周转时间
public static void main(String[] args) {
init(); //初始化进程队列
input(); //对进程列表的录入
List<Process> list = SJF();
for (Process process: list) {
System.out.println("进程名:"+process.getJobName()+
",到达时间:"+process.getTimeOfArrival()+
",运行时间:"+process.getServiceHours()+
",开始执行时间:" + process.getStartExecutionTime()+
",完成时间:"+process.getCompleteTime()+
",周转时间:"+process.getTurnaroundTime()+
",带权周转时时间:"+process.getWeightedTurnaroundTime()+
",等待时间:"+process.getWritTime());
}
calculateTheAverage(list);
System.out.println("处理总时间为:"+time+
",平均周转时间:"+averageTurnaroundTime+
",平均带权周转时间:"+averageWeightedTurnaroundTime+
",平均等待时间:"+averageWaitingTime);
}
/**
* 初始化进程队列
*/
private static void init(){
System.out.println("请输入要处理的线程数:");
Scanner scanner = new Scanner(System.in);
int length = scanner.nextInt();
for (int i = 0;i<length;i++){
processList.add(new Process());
}
System.out.println("初始化完成");
}
/**
* 向队列中输入要处理的数据
* 进程的一些信息
*/
private static void input(){
Scanner scanner = new Scanner(System.in); //创建输入类
Process process = null;
for (int i = 0;i<processList.size();i++){
process = processList.get(i);
System.out.println("请输入第"+(i+1)+"个进程名:");
process.setJobName(scanner.next());
System.out.println("请输入第"+(i+1)+"个进程的到达时间:");
process.setTimeOfArrival(scanner.nextFloat());
System.out.println("请输入第"+(i+1)+"个进程的服务(运行)时间:");
process.setServiceHours(scanner.nextFloat());
process.setStatus("创建态");
}
System.out.println("信息录入完成");
}
/**
* 返回进程队列中最先到达的进程的下标
* @return 队列中最先到达的进程下标
*/
private static int findMinSubscript(){
float min = processList.get(0).getTimeOfArrival();
for (Process process: processList) {
if(min > process.getTimeOfArrival()){
min = process.getTimeOfArrival();
}
}
//循环过后,min就是队列中达到时间最短的线程的值
for (int i = 0 ;i<processList.size();i++){
if(min == processList.get(i).getTimeOfArrival()){
return i;
}
}
return 0;
}//下标
/**
* 对进程队列进行判断,并将符合条件的进程状态改为阻塞态
*/
private static void whetherToBlock(){
if (time == null){//到系统时间为空时
return;
}
for (Process process : processList){
if(time >= process.getTimeOfArrival()){
process.setStatus("阻塞态");
}
}
}//是否阻塞
/**
* 返回队列中服务时间最短的线程下标
* 但现成的状态必须为阻塞态
* @return
*/
private static int ShortServiceTime(){
int index = findMinSubscript(); //因为运行此函数时,系统已经处理过至少一个进程块了
float min = processList.get(index).getServiceHours(); //返回出去第一个进程过后的最小服务时间
//找到最小服务时间
for (int i =0;i<processList.size();i++){
if(processList.get(i).getStatus().equals("阻塞态")){
if(min > processList.get(i).getServiceHours()){
min = processList.get(i).getServiceHours();
}
}
}
//根据最小服务时间返回对应的下标
for (int i = 0;i<processList.size();i++){
if (processList.get(i).getServiceHours() == min){
return i;
}
}
return -1;
}//最短服务时间
/**
* SJF非抢占式
*/
private static List<Process> SJF(){
List<Process> completionQueue = new ArrayList<>();//完成队列
while (processList.size() != 0){
int index = findMinSubscript(); //先找到进程队列中达到时间最小的时间
Process process = processList.get(index); //得到对应
//系统刚开始处理进程队列
if(time == null){
//第一个被处理的进程块的 开始时间 = 到达时间
process.setStartExecutionTime(process.getTimeOfArrival());
//完成时间 = 开始运行时间 + 运行(服务)时间
process.setCompleteTime(process.getStartExecutionTime() + process.getServiceHours());
//周转时间 = 完成时间 - 到达时间
process.setTurnaroundTime(process.getCompleteTime() - process.getTimeOfArrival());
//带权周转时间 = 周转时间 / 运行(服务)时间
process.setWeightedTurnaroundTime(process.getTurnaroundTime() / process.getServiceHours());
//等待时间 = 周转时间 - 运行时间
process.setWritTime(process.getTurnaroundTime() - process.getServiceHours());
//此时系统时间 = 给进程的完成时间
time = process.getCompleteTime();
}else {
//如果前一个完成时间 ,小于到达时间,系统有空闲
if(time < process.getTimeOfArrival()){
float idle = process.getTimeOfArrival() - time;//空闲出来的时间
time += idle;
}
//判断其他进程的状态
whetherToBlock();
//找到最短服务时间的进程下标
index = ShortServiceTime();
process = processList.get(index);
//排除第一个进程 开始执行时间 = 系统时间
process.setStartExecutionTime(time);
//完成时间 = 开始执行时间 + 服务时间(运行时间)
process.setCompleteTime(process.getStartExecutionTime() + process.getServiceHours());
//周转时间 = 完成时间 - 到达时间
process.setTurnaroundTime(process.getCompleteTime() - process.getTimeOfArrival());
//带权周转时间 = 周转时间 / 运行时间(服务时间)
process.setWeightedTurnaroundTime(process.getTurnaroundTime() / process.getServiceHours());
//等待时间 = 周转时间 - 运行时间
process.setWritTime(process.getTurnaroundTime() - process.getServiceHours());
//修正系统时间 此时系统时间 = 原来系统时间 + 此进程的完成时间(服务时间)
time += process.getServiceHours();
}
//进程的状态变为终止态
process.setStatus("终止态");
//将该线程添加进完成队列之中
completionQueue.add(process);
//将该线程从原先对列移出
processList.remove(index);
}
return completionQueue;
}
/**
* 根据传入的集合
* 计算平均周转时间、平均带权周转时间、平均等待时间
*/
public static void calculateTheAverage(List<Process> processList){
float turnaroundTime = 0;//总周转时间
float weightedTurnaroundTime = 0;//总带权周转时间
float waitingTime = 0;//总等待时间
for (Process process: processList) {
turnaroundTime += process.getTurnaroundTime();
weightedTurnaroundTime += process.getWeightedTurnaroundTime();
waitingTime += process.getWritTime();
}
averageTurnaroundTime = turnaroundTime / processList.size();
averageWaitingTime = waitingTime / processList.size();
averageWeightedTurnaroundTime = weightedTurnaroundTime / processList.size();
}//计算平均
}
由于Java的GUI几乎都不使用了(当然我也不会),控制台打印又台low了,所以我写完这些就将代码转移为JavaScript实现了,所以两个算法的实现是分了两个mian函数的,又很多重复的代码,如果你想要使用,建议将两个类的main函数整合为一个。
实验总结和分析
- 通过本次实验,让我了解了操作系统对进程作业调度的工作机制,体会到了两个作业调度的优点和缺点,加深了我对操作系统在作业调度方面的学习。
- 通过Java程序对两种算法的实现,加强了我的Java代码的程序设计,巩固了我的JavaSE的基础,增强了自身的业务处理逻辑,让我熟悉了程序语言的执行流程。
- 这次实验增强了我的动手实践能力,让自己所想的逻辑能够通过编程语言实现,让我对编程对计算机操作系统产生了很深的兴趣。
- 对于代码的实现,还是有很多需要优化和改进的方面,比如
findMinSubscript()
返回最先到达的进程下标的函数和用到该函数的一些功能完全可以通过ArrayList提供的根据对象的某一属性进行排序的内部方法实现,既缩短了代码的长度,又使代码逻辑更加的通俗易懂。
个人感觉实验总结和分析写得不是太好,不喜欢得可以去找一些网上找其他的优秀博客,至于我为什么要写这个实验总结呢??懂得都懂嘛,这是互联网为我们提供的便利嘛。当然个人建议是自己独立完成实验的好。
下面是我用学的蹩脚的前端实验的,代码写的很烂,所以想了解可以了解,不想了解这篇文章就已经结束了。
前端实现(HTML+CSS+JavaScript+Jquery)
项目结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SxhCPvvz-1621940033660)(/image-20210525145922118.png)]
作业调度算法.html
使用到的jquery1.8.3大家可以在网上自行下载!
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>作业调度算法</title>
<!--这里使用的jquery1.8.3-->
<script src="./js/jquery-1.8.3.min.js"></script>
<style>
*{
padding: 0;
margin: 0;
}
body{
width: 100wh;
height: 100vh;
overflow: hidden;
/* background: url('./imgs/bg.png') center no-repeat; */
}
.Display_data{
text-align: center;
}
.Display_data .make button{
margin: auto;
}
.form table{
background: #0f6d6048;
margin: auto;
margin-top: 40px;
}
th td{
width: 205px;
height: 41px;
}
button{
width: 100%;
height: 100%;
}
.Datavisual{
width: 600px;
height: 100px;
float: left;
overflow: hidden;
text-align: center;
font-size: 25px;
line-height: 100px;
margin-top: 40px;
margin-left: 33.8%;
/* background: rgb(197, 49, 49,.5); */
/* position: relative; */
}
.child{
/* position: absolute; */
transition:2s;
background: red;
float: left;
height: 100%;
}
</style>
</head>
<body>
<div class="Display_data">
<div class="form">
<table border="1px">
<thead>
<tr>
<th >进程名</th>
<th>到达时间</th>
<th>服务时间</th>
<!-- 隐藏内容 -->
<th class="Hidden_content" hidden>开始执行时间</th>
<th class="Hidden_content" hidden>完成时间</th>
<th class="Hidden_content" hidden>周转时间</th>
<th class="Hidden_content" hidden>带权周转时间</th>
<th class="Hidden_content" hidden>等待时间</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<input class="process_name" type="text">
</td>
<td>
<input class="time_of_arrival" type="number">
</td>
<td>
<input class="service_hours" type="number">
</td>
<td class="Hidden_content startExecutionTime" hidden ></td>
<td class="Hidden_content completeTime" hidden></td>
<td class="Hidden_content turnaroundTime" hidden ></td>
<td class="Hidden_content weightedTurnaroundTime" hidden></td>
<td class="Hidden_content writTime" hidden></td>
</tr>
</tbody>
<tfoot>
<tr>
<td>
<button id="add" onclick="add()">添加一行</button>
</td>
<td>
<button id="del" onclick="del()">删除一行</button>
</td>
<td>
<button type="button" onclick="javascript:location.reload()">重置</button>
</td>
</tr>
<tr>
<td>
<button onclick="operatingForFSFC()">FSFC先到先服务</button>
</td>
<td>
<button onclick="operatingForSJF()">SJF短作业优先</button>
</td>
<td>
<button onclick="experiment()">这个按钮没用</button>
</td>
</tr>
</tfoot>
</table>
<div class="shou"></div>
</div>
<!-- 数据可视化 -->
<div class="Datavisual"></div>
</div>
<script>
//实验
function experiment(){
if($('.Datavisual').css('width') == '0px'){
$('.Datavisual').css({
'transition-duration':'2s',
'background':'red',
'width':'600px'
});
}
if($('.Datavisual').css('width') == '600px'){
$('.Datavisual').css({
'transition-duration':'0s',
'width':'0px',
'background':''
});
}
}
//增加一行
function add(){
$('table tbody').append('<tr><td><input class="process_name" type="text"></td><td><input class="time_of_arrival" type="number"></td><td><input class="service_hours" type="number"></td><td class="Hidden_content startExecutionTime" hidden></td><td class="Hidden_content completeTime" hidden></td><td class="Hidden_content turnaroundTime" hidden></td><td class="Hidden_content weightedTurnaroundTime" hidden></td><td class="Hidden_content writTime" hidden></td></tr>');
}
//删除一行
function del(){
var arr = $('table tbody tr');
if(arr.length > 0){
var last = arr.length;
arr[last-1].remove();
}
}
//计算 FSFC算法实现
function operatingForFSFC(){
if(init()){ //先对用户输入的信息进行读取
var complete_array = FSFC();//完成数组,接收返回的进程队列
//调用方法,处理过的数据,呈现给用户
showData(complete_array);
Datavisual(complete_array);
//对使用过的全局变量初始化
complete_array.length = 0;
PCB.length = 0;
time = '';
}
}
//计算 SJF算法实现
function operatingForSJF(){
if(init()){ //先对用户输入的信息进行读取
var complete_array = SJF();//完成数组,接收返回的进程队列
//调用方法,处理过的数据,呈现给用户
showData(complete_array);
Datavisual(complete_array);
complete_array.length = 0;
PCB.length = 0;
time = '';
}
}
//FSFC要实现的主要脚本
const PCB = new Array(); //进程队列
var time = ''; //初始化系统时间
//用于计算算法实现的平均值,使用过后,要回复初始值
//初始值赋值为 '',防止于计算出来的数值冲突
var averageTurnaroundTime = ''; //平均周转时间
var averageWaitingTime = ''; //平均等待时间
var averageWeightedTurnaroundTime = ''; //平均带权周转时间
var executionOrder = ''; //执行顺序
//获取到用户输入的数值,当数值不合法时,弹窗警告并退出
function init(){
var process_name = $('.process_name');
var time_of_arrival = $('.time_of_arrival');
var service_hours = $('.service_hours');
var length = $('.form table tbody tr').length;
//对输入的数据进行检索
if(!examination(process_name)){
return false;
}
if(!examination(time_of_arrival)){
return false;
}
if(!examination(service_hours)){
return false;
}
//将各个输入框的值读取到PCB数组中
for(var i = 0; i < length; i++){
var prescss = {}; //进程
prescss.process_name = process_name[i].value;
prescss.time_of_arrival = time_of_arrival[i].value * 1; //转化为数字
prescss.service_hours = service_hours[i].value * 1;
PCB.push(prescss);
}
return true;
}
//检查数据是否为空
function examination(object){
for(var i =0;i < object.length;i++){
if(object[i].value == ''){
alert("输入的数据不能为空,请检查");
return false;
}
if(object[i].value < 0){
alert("请不要输入负数");
return false;
}
}
return true;
}
//发现PCB数组中最先到达的进程
function findMinForTime_of_arrival(){
//程序正常运行,不被别人恶意更改代码执行的顺序,PCB 的长度不可能会是0
if(PCB.length == 0){
alert("PCB进程处理队列为空");
return;
}
var min = PCB[0].time_of_arrival;
//迭代遍历,获得最先到达进程的时间(获取最小值)
PCB.forEach(prescss =>{
if(min > prescss.time_of_arrival){
min = prescss.time_of_arrival;//
}
});
//根据最小值,获取并返回对应数组下标
for(var i =0 ;i<PCB.length;i++){
if(PCB[i].time_of_arrival == min){
return i;
}
}
}
//FSFC先到先服务算法的实现
// 每次获得先到的进程,然后取出对应的进程,并放到完成队列中,循环执行,直到PCB中的进程全部放到完成队列中
function FSFC(){
const carry_out = new Array(); //完成队列
var index = 0;
while(PCB.length != 0){
index = findMinForTime_of_arrival();
var prescss = PCB[index]; //获取到对应进程
if(time == ''){ //系统刚开始处理进程
//第一个被处理的进程 开始执行时间 = 该进程的到达时间
prescss.startExecutionTime = prescss.time_of_arrival;
//完成时间 = 开始执行时间 + 运行(服务)时间
prescss.completeTime = prescss.startExecutionTime + prescss.service_hours;
//周转时间 = 完成时间 - 到达时间
prescss.turnaroundTime = prescss.completeTime - prescss.startExecutionTime;
//带权周转时间 = 周转时间 / 运行(服务)时间
prescss.weightedTurnaroundTime = prescss.turnaroundTime / prescss.service_hours;
//等待时间 = 周转时间 - 运行(服务)时间
prescss.writTime = prescss.turnaroundTime - prescss.service_hours;
//此时系统时间 = 该进程的完成时间
time = prescss.completeTime;
}else{//出去第一个先到达的进程,其余进程的处理
//如果 第一个 / 前一个 进程的完成时间小于 第二个 / 此代码块正在处理的进程
if(time < prescss.time_of_arrival){
//前一个进程的完成时间 = 系统时间
//前一个进程处理完了,但后一个进程还没到达,系统空闲
var idle = prescss.time_of_arrival - time; //得到空闲时间是多少
time += idle; //想到于系统度过空闲出的进程
}
//排除第一个进程的处理 后面的进程的处理方法
//开始时间 = 系统时间
prescss.startExecutionTime = time; //这里是于第一个进程处理公式不一样的地方
//后面的处理步骤(处理最后一步修正系统时间不一致之外),与第一个进程的处理步骤一致
//完成时间 = 开始执行时间 + 服务(运行)时间
prescss.completeTime = prescss.startExecutionTime + prescss.service_hours;
//周转时间 = 完成时间 - 到达时间
prescss.turnaroundTime = prescss.completeTime - prescss.time_of_arrival;
//带权周转时间 = 周转时间 / 运行(服务)时间
prescss.weightedTurnaroundTime = prescss.turnaroundTime / prescss.service_hours;
//等待时间 = 周转时间 - 运行时间
prescss.writTime = prescss.turnaroundTime - prescss.service_hours;
//修正系统的时间 排除第一个进程 系统的时间 = 原先的系统时间 + 正在处理进程的运行时间
time += prescss.service_hours;
//这里方法不一,也可以是:系统时间 = 此进程的完成时间
}
//将处理完成的进程添加到完成队列之中
prescss.status = "创建态"; //将进程的状态 写入到进程对象中 这里FSFC并没有用,主要是同步后面的SJF
carry_out.push(prescss);
//将处理过的进程从PCB队列之中移出
PCB.splice(index,1); //达到队列往下进行的作用,(关键一步)
}
return carry_out;
}
//非抢占式断进程优先服务
function SJF(){
const carry_out = new Array(); //定义完成队列
while(PCB.length != 0){
var index = findMinForTime_of_arrival(); //先找到进程队列中到达时间最小的时间
var process = PCB[index]; //得到对应的进程
//系统刚开始处理进程队列
if(time == ''){
//第一个被处理的进程块 开始时间 = 到达时间
process.startExecutionTime = process.time_of_arrival;
//完成时间 = 开始运行时间 + 运行(服务)时间
process.completeTime = process.startExecutionTime + process.service_hours;
//周转时间 = 完成时间 - 到达时间
process.turnaroundTime = process.completeTime - process.time_of_arrival;
//带权周转时间 = 周转时间 / 运行(服务)时间
process.weightedTurnaroundTime = process.turnaroundTime / process.service_hours;
//等待时间 = 周转时间 - 运行时间
process.writTime = process.turnaroundTime - process.service_hours;
//此时的系统时间 = 该进程的完成时间
time = process.completeTime;
}else{
//如果前一个完成时间,小于到达时间,系统又空闲
if(time < process.time_of_arrival){
var idle = process.time_of_arrival - time; //得到空闲出来的时间
time += idle; //修正系统时间
}
//判断其他进程的状态
whetherToBlock();
//找到最短服务时间的进程下标
index = findMinForService_hours();
//获取最短服务的进程对象
process = PCB[index]; //这个是本次循环要操作计算的对象
//排除第一个进程 开始执行时间 = 系统时间
process.startExecutionTime = time;
//完成时间 = 开始时间 + 服务(运行)时间
process.completeTime = process.startExecutionTime + process.service_hours;
//周转时间 = 完成时间 - 到达时间
process.turnaroundTime = process.completeTime - process.time_of_arrival;
//带权周转时间 = 周转时间 / 运行(服务)时间
process.weightedTurnaroundTime = process.turnaroundTime / process.service_hours;
//等待时间 = 周转时间 - 运行时间
process.writTime = process.turnaroundTime - process.service_hours;
//此时的系统时间 = 原来的系统时间 + 该进程的服务(运行)时间
time += process.service_hours;
}
//让进程进入到终止状态,这里是为了区分其他没有 创建态 阻塞态
//其实没有什么作用
process.status = "终止态";
//将该线程 添加到 完成队列(其实是数组)中去
carry_out.push(process);
//将该线程从PCB队列中移除,因为已经让PCB处理过了
PCB.splice(index,1); //关键一步
}
return carry_out; //将装了处理过后的进程数组返回,一供后续函数使用
}
//对进程中各个进程的状态进行判断,将符合状态的进程该为阻塞态
function whetherToBlock(){
if(time == ''){
//系统还未处理进程,各个进程处在还没有创建的状态,程序中不会出现
return;
}
//迭代循环
PCB.forEach(process =>{
if(time >= process.time_of_arrival){
//如果此时系统时间大于或等于进程的到达时间,说明进程已经准备好被PCB处理了
//将进程的状态修改为 阻塞态 可能不符合各个进程的真实状态
//但这里只是作为标记,方便SJF算法的实现,不纠结这个
process.status = "阻塞态";
}
});
}
//返回队列中服务时间最短的进程下标
// 但要在进程出于阻塞状态时 才符合条件
function findMinForService_hours(){
var index = findMinForTime_of_arrival(); //运行此函数时,系统已经处理过至少一个进程了
var min = PCB[index].service_hours;//返回到达时间最短的进程的服务时间
//找到最小服务时间
//迭代循环
PCB.forEach(process =>{
//先判断进程的状态是否是阻塞态
if(process.status == "阻塞态"){
//是阻塞态 才有权比较是否是最短服务时间
if(min > process.service_hours){
min = process.service_hours;
}
}
});
//根据找到的最小的服务时间,返回对应的进程下标
for(var i =0;i<PCB.length;i++){
if(PCB[i].service_hours == min){
return i; //返回对应的下标
}
}
}
//将处理过后的数据显示给用户
function showData(dataArr){
//判断传入的数据是否没有进程 程序正常运行 不会出现
if(dataArr.length <= 0){
return;
}
//显示表格
var all_hidden = $('.Hidden_content');
for(var i = 0;i<all_hidden.length;i++){
$(all_hidden[i]).removeAttr('hidden');
}
//获取行数
var number_of_lines = $('tbody tr').length;
//获取列
var process_name = $('.process_name');
var time_of_arrival = $('.time_of_arrival');
var service_hours = $('.service_hours');
var startExecutionTime = $('.startExecutionTime');
var completeTime = $('.completeTime');
var turnaroundTime = $('.turnaroundTime');
var weightedTurnaroundTime = $('.weightedTurnaroundTime');
var writTime = $('.writTime');
//将carray_out中装的信息 显示给用户
for(var i =0;i<number_of_lines;i++){
var prescss = dataArr[i];
// var index = i * column.length;
process_name[i].value = prescss.process_name;
time_of_arrival[i].value = prescss.time_of_arrival;
service_hours[i].value = prescss.service_hours;
startExecutionTime[i].innerHTML = (prescss.startExecutionTime);
completeTime[i].innerHTML = (prescss.completeTime);
turnaroundTime[i].innerHTML = (prescss.turnaroundTime);
weightedTurnaroundTime[i].innerHTML = (prescss.weightedTurnaroundTime);
writTime[i].innerHTML = (prescss.writTime);
}
//计算各个平均值和显示进程的执行顺序
Average(dataArr);
}
//计算平均值和显示进程的执行顺序
function Average(dataArr){
//传入的数组不合法
if(dataArr.length <= 0){
return;
}
//计算算法
var turnaroundTime = 0; //总周转时间
var weightedTurnaroundTime = 0; //总带权周转时间
var waitingTime = 0; //总等待时间
dataArr.forEach(process =>{
executionOrder += process.process_name;
executionOrder += "-->";
turnaroundTime += process.turnaroundTime;
weightedTurnaroundTime += process.weightedTurnaroundTime;
waitingTime += process.writTime;
});
//对各个平均值进行赋值
averageTurnaroundTime = turnaroundTime / dataArr.length;
averageWeightedTurnaroundTime = weightedTurnaroundTime / dataArr.length;
averageWaitingTime = waitingTime / dataArr.length;
//显示计算出来的平均值
if($('p.text').length != 5){
//页面还没有添加p元素
$('.shou').append('<p style="color:red" class="text">执行顺序:'+executionOrder+'</p>');
$('.shou').append('<p style="color:red" class="text">平均周转时间:'+averageTurnaroundTime+'</p>');
$('.shou').append('<p style="color:red" class="text">平均带权周转时间:'+averageWeightedTurnaroundTime+'</p>');
$('.shou').append('<p style="color:red" class="text">平均等待时间:'+averageWaitingTime+'</p>');
$('.shou').append('<p style="color:red" class="text">总耗时:'+time+'</p>');
}else{
//页面已经有p元素了
var msgArr = $('p.text');
$(msgArr[0]).text('执行顺序:'+executionOrder);
$(msgArr[1]).text('平均周转时间:'+averageTurnaroundTime);
$(msgArr[2]).text('平均带权周转时间:'+averageWeightedTurnaroundTime);
$(msgArr[3]).text('平均等待时间:'+averageWaitingTime);
$(msgArr[4]).text('总耗时:'+time);
}
//清空数据
executionOrder = '';
averageTurnaroundTime = '';
averageWeightedTurnaroundTime = '';
averageWaitingTime = '';
}
//数据可视
function Datavisual(dataArr){
$($('.Datavisual').get(0)).css('banckground','');
$('.Datavisual').text(' ');
//这里函数调用时,time各个数据还没有被初始化
//函数的功能是显示各个进程的服务时间,出入的数组是完成队列的数据
//函数开始先将class= child的div清除掉
var arr = $('.child');
for(var i =0;i<arr.length;i++){
arr[i].remove();
}
//重新创建
for(var i =0;i<dataArr.length;i++){
$('.Datavisual').append('<div class="child"></div>');
}
//显示数据
var unit = 600/time; //单位
var child = $('.child');
for(var i =0;i<dataArr.length;i++){
var process = dataArr[i];//进程
var rgba = randomColor();
$(child[i]).css({
'background':'rgba('+rgba.r+','+rgba.g+','+rgba.b+','+rgba.a+')',
'width':process.service_hours*unit+'px',
});
$(child[i]).text(process.process_name);
}
}
// console.log(randomColor().r);
//返回随机生成的rgba颜色值
function randomColor(){
var color = {};
color.r = (Math.ceil(255*Math.random()));
color.g = (Math.ceil(255*Math.random()));
color.b = (Math.ceil(255*Math.random()));
color.a = (0.1+(Math.random()*0.9)).toFixed(1)*1;
return color;
}
</script>
</body>
</html>
实验总结和分析
- 通过本次实验,让我了解了操作系统对进程作业调度的工作机制,体会到了两个作业调度的优点和缺点,加深了我对操作系统在作业调度方面的学习。
- 本实验是通过前端的技术实现,可以让使用者体会到作业两种作业调度的差异,也增强了自己的前端的实现能力,增强了自己的对前端业务处理的能力。
- 这次实验增强了我的动手实践能力,让自己所想的逻辑能够通过编程语言实现,让我对编程对计算机操作系统产生了很深的兴趣。
- 本次实验的业务逻辑虽然通过前端实现了,但是对数据的展现太过于生硬,自己对jquery框架的掌握和将它运用在自己项目中的能力还有待提升。