处理机调度算法模拟实验
一、实验目的
本实验模拟在单处理机情况下的处理机调度算法,用某种编程语言实现先来先服务和最短作业优先调度算法的模拟。
二、实验原理
1、先来先服务调度算法原理:
先来先服务调度算法,类似于队列,先进先出,后进后出。
输入进程后依据进程的提交时间进行排序。
1.怎么计算每个作业的运行时间? 运行时间就是作业需要运行的时间。
2.怎么计算每个作业的结束时间?
先维护一个成员变量作为当前时间,
当前时间初始化为第一个作业进入的时间
每进入一个作业,当前时间就加上该作业的 运行时间
每个作业的结束时间就是当前时间。
3.怎么计算周转时间?
周转时间=作业结束时间—作业提交时间。
4.怎么计算平均周转时间?
平均周转时间=周转时间/作业个数。
2、短作业优先调度算法原理为:
在作业调度中,该算法每完成一个作业,就从后续所有到达队列的作业中找到运转时间最短的一个调入内存,分配必要的资源,创建进程并放入就绪队列。SJF是非抢占式的调度算法,优先照顾短作业,具有较好的性能,降低了平均等待时间,提高作业的吞吐量。但另一方面,由于短作业优先,长作业可能超时间处于等待状态,不能用于实时系统。
先输入所有作业的条件,录入到顺序表中
对所有作业按到达时间排序,将到达时间最小的作业调入内存
然后将剩下作业按运转时间升序排序,依次进入内存作业
结束后输出作业时间,平均周转时间
三、实验要求
上机前必须认真的做好准备,了解FCFS和短作业优先调度算法原理;
四、实验内容
1、问题描述
假设有三个作业,他们的作业号、提交时间、需要运行的时间如下:
作业号 | 提交时间 | 需要运行的时间 |
1 | 0 | 6 |
2 | 2 | 4 |
3 | 3 | 2 |
(1)如果使用FCFS调度算法,请问这三个作业的执行顺序是什么样的,并基于此执行顺序计算它们的周转时间、平均周转 时间,计算后将结果填入下表。
三个作业的执行情况分析(FCFS):
作业执行顺序 | 提交时间 | 运行时间 | 开始时间 | 结束时间 | 周转 时间 | 平均周 转时间 |
1 | 0 | 6 | 0 | 6 | 6 | 7.6 |
2 | 2 | 4 | 6 | 10 | 8 | |
3 | 3 | 2 | 10 | 12 | 9 |
(2)如果使用短作业优先调度算法,请问这三个作业的执行顺序是什么样的,并基于此执行顺序计算它们的周转时间、平均周转时间,计算后将结果填入下表。
三个作业的执行情况分析(SJF):
作业执行顺序 | 提交时间 | 运行时间 | 开始时间 | 结束时间 | 周转 时间 | 平均周 转时间 |
1 | 0 | 6 | 0 | 6 | 6 | 7 |
3 | 3 | 2 | 6 | 8 | 5 | |
2 | 2 | 4 | 8 | 12 | 10 |
2、代码设计
用某种编程语言模拟FCFS和SJF调度算法,加深对进程调度算法的认识,并将代码复制粘贴在本段下方。要求程序首先由用户输入要运行的作业数,然后选择进程调度算法,并依次输入各个作业的基本信息,包括作业号、提交作业时间、需要运行的时间,代码会分析整个作业调度执行过程,并计算出各个作业的开始执行时间、结束运行时间、周转时间、平均周转时间。
FCFS算法:
Main类:
package fcfs;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
ArrayList<Work> works = new ArrayList<>(); //储存作业
System.out.println("请输入作业个数");
int n = sc.nextInt();
//把需要进行的作业添加到works
for (int i = 0; i < n; i++) {
System.out.println("请输入作业的编号、提交时间、运行时间");
int id = sc.nextInt();
int startTime = sc.nextInt();
int runTime = sc.nextInt();
Work work = new Work(id,startTime,runTime);
works.add(work);
}
LinkSort(works,0,works.size()-1);
double time = works.get(0).getStartTime();
double turnvoerTimeSum=0;
//每个作业的值
for (Work work : works) {
if(time<work.getStartTime()) time = work.getStartTime();
work.setStartRunTime(time);
time += work.getRunTime();
work.setFinalTime(time);
work.setTurnoverTime(time-work.getStartTime());
turnvoerTimeSum+=work.getTurnoverTime();
}
double turnvoerTimeAverage=turnvoerTimeSum/n;
System.out.println("编号\t\t\t提交时间\t\t\t开始时间\t\t\t运行时间\t\t\t结束时间\t\t\t周转时间");
for (Work work : works) {
workOut(work);
}
System.out.println("平均周转时间为:"+turnvoerTimeAverage);
}
//根据作业的提交时间进行排序
public static void LinkSort(ArrayList<Work> works,int l,int r){
if(l>=r) return ;
Work x = works.get(l+r>>1);
int i = l-1,j = r+1;
while(i<j){
do i++;while(works.get(i).getStartTime()<x.getStartTime());
do j--;while(works.get(j).getStartTime()>x.getStartTime());
Collections.swap(works,i,j);
}
LinkSort(works,l,j);
LinkSort(works,j+1,r);
}
public static void workOut(Work work){
System.out.println(work.getId()+" "+work.getStartTime()+" "+work.getStartRunTime()+" "+work.getRunTime()+" "+work.getFinalTime()+" "+work.getTurnoverTime());
}
}
Work类:
package fcfs;
public class Work {
private int id;
private double startTime;
private double startRunTime;
public double getStartRunTime() {
return startRunTime;
}
public void setStartRunTime(double startRunTime) {
this.startRunTime = startRunTime;
}
private double runTime;
private double finalTime;
private double turnoverTime;
public double getFinalTime() {
return finalTime;
}
public void setFinalTime(double finalTime) {
this.finalTime = finalTime;
}
public double getTurnoverTime() {
return turnoverTime;
}
public void setTurnoverTime(double turnoverTime) {
this.turnoverTime = turnoverTime;
}
public Work(int id, double startTime, double runTime) {
this.id = id;
this.startTime = startTime;
this.runTime = runTime;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getStartTime() {
return startTime;
}
public void setStartTime(double startTime) {
this.startTime = startTime;
}
public double getRunTime() {
return runTime;
}
public void setRunTime(double runTime) {
this.runTime = runTime;
}
}
SJF调度算法:
#include <iostream>
#include<algorithm>
using namespace std;
string name;
int reachtime;
int usetime;
double averagewaittime;
int alltime = 0;
class node
{
public:
int name;//作业名 到达时间 运行时间 开始运行时间 结束运行时间 周转时间 是否运行过
int reachtime;
int usetime;
int starttime;
int useendtime;
int waittime;
bool yn;
};
node* arr = new node[100];
node* brr = new node[100];
void push(int x)
{
cout << "请输入作业号 进入时间 作业时间" << endl;
for (int i = 0; i < x; i++)
{
cin >> arr[i].name >> arr[i].reachtime >> arr[i].usetime;
arr[i].yn = 1;
}
}
bool cmp1(node cs1, node cs2)//重载sort,到达时间 运行时间 作业名
{
return cs2.reachtime > cs1.usetime;
}
bool cmp2(node cs1, node cs2)
{
return cs1.usetime < cs2.usetime;
}
bool cmp3(node cs1, node cs2)
{
return cs1.name < cs2.name;
}
int main()
{
int x, xcode, i = 1;
cout << "作业总数为:" << endl;
cin >> x;
xcode = x ;
push(x);
sort(arr, arr + x, cmp1);
arr[0].starttime = arr[0].reachtime;
arr[0].useendtime = arr[0].reachtime + arr[0].usetime;
arr[0].waittime = arr[0].useendtime - arr[0].reachtime;
arr[0].yn = 0;
alltime += arr[0].useendtime;
sort(arr + 1, arr + x, cmp2);
while (xcode-1)
{
if (arr[i].reachtime <= alltime && arr[i].yn == 1)
{
arr[i].starttime = alltime;
arr[i].useendtime = arr[i].usetime + alltime;
arr[i].waittime = arr[i].useendtime - arr[i].reachtime;
alltime = arr[i].useendtime;
xcode--;
i++;
}
else if (arr[i].reachtime > alltime && arr[i].yn == 1)
{
alltime = arr[i].reachtime;
arr[i].useendtime = arr[i].usetime + alltime;
arr[i].waittime = arr[i].usetime;
arr[i].starttime = alltime;
alltime = arr[i].useendtime;
xcode--;
i++;
}
else if (arr[i].yn == 0)
{
i++;
}
else if (i >= x)
{
i = 1;
}
}
sort(arr, arr + x, cmp3);
cout << "以下分别为作业号 提交时间 需要运行的时间 开始运行时间 运行结束时间 周转时间" << endl;
for (int cx = 0; cx < x; cx++)
{
cout << arr[cx].name << " " << arr[cx].reachtime << " " << arr[cx].usetime << " " << arr[cx].starttime << " " << arr[cx].useendtime << " " << arr[cx].waittime << endl;
averagewaittime += arr[cx].waittime;
}
averagewaittime = averagewaittime / (double)x;
cout << "平均周转时间为:" << averagewaittime << endl;
return 0;
}
3、实验验证
用编写好的代码验证实验内容1中作业的执行情况,看代码运行结果是否与之前的分析计算结果一致,并将执行界面进行截图。
(1)FSFC调度算法
(2)SJF调度算法
五、实验中遇到的问题及解决方法,以及对作业的自我评价和反思。
FCFS 先来先服务:优点:公平、算法实现简单; 缺点:排在长作业(进程)后面的短作业需要等待很长时间,带权周转时间很大,对短作业来说用户体验不好。即,FCFS算法对长作业有利,对短作业不利
SJF 短作业优先 :优点:“最短的”平均等待时间、平均周转时间。缺点:不公平。对短作业有利,对长作业不利。可能产生饥饿现象。另外,作业/进程的运行时间是由用户提供的,并不一定真实,不一定能做到真正的短作业优先。如果源源不断地有短作业/进程到来,可能使长作业/进程长时间得不到服务,产生“饥饿”现象。如果一直得不到服务,则称为“饿死”
通过这次实验,加深了我对于不同种处理机调度算法的理解,包括不同算法的原理,特点,优缺点等。通过实际的测试用例,让我们对不同调度算法的工作流程和规则更加熟悉。同时,也提升了自己的编程能力,受益匪浅。