1 处理机的调度层次和调度算法目标
2 批处理系统中的作业调度
2.1 先来先服务调度算法(first-come first-served,FCFS)
描述:FCFS是最简单的调度算法,该算法可用于作业调度,也可用于进程调度,当在作业调度中采用该算法时,系统将按照作业到达的先后次序进行调度,或者说优先考虑在系统中等待时间最长的作业,而不管作业需要执行时间的长短,从后背作业队列中选择几个最先进入该队列的作业,将他们调入内存,为他们分配资源和创建进程,最后放入就绪队列。
当在进程中采用该算法时,每次调度从就绪的进程队列中选择一个最先进入该队列的进程,为之分配处理机,投入运行。该进程一直运行到完成或者发生某个时间阻塞时,进程调度将处理机分配给其他进程。
算法实现:
// Fsc.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "pch.h"
#include <iostream>
using namespace std;
int main()
{
int countHomework;
cout << "请输入作业数量:" << endl;
cin >> countHomework;
double **arr = new double *[countHomework];
for (int i = 0;i < countHomework;i++)
{
arr[i] = new double[5];
}
for (int i = 0;i < countHomework;i++)//初始化
for (int j = 0;j < 5;j++)
arr[i][j] = 0;
double starttime, endtime;
cout << "请输入开始时间和运行时间" << endl;
for (int i = 0;i < countHomework;i++) {
cin >> starttime >> endtime;
arr[i][1] = starttime;
arr[i][2] = endtime;
}
//排序
double temp_1;
double temp_2;
for (int i = 0;i < countHomework;i++)
{
for (int j = i + 1;j < countHomework;j++)
{
if (arr[i][1] > arr[j][1])
{
temp_1 = arr[i][1];
temp_2 = arr[i][2];
arr[i][1] = arr[j][1];
arr[i][2] = arr[j][2];
arr[j][1] = temp_1;
arr[j][2] = temp_2;
}
}
}
double currentTime;
currentTime = arr[0][1];
arr[0][3] = currentTime+arr[0][2];//作业完成时间
currentTime = arr[0][3];
arr[0][4] = currentTime-arr[0][1];//周转时间
for (int i = 1;i < countHomework;i++)
{
arr[i][3] = currentTime + arr[i][2];//计算完成时间
currentTime += arr[i][2];
arr[i][4] = currentTime - arr[i][1];//计算周转时间
}
cout << "进程号\t" << "开始时间\t" << "运行时间\t" <<"完成时间\t"<< "周转时间\t" << endl;
for (int i = 0;i < countHomework;i++) {
arr[i][0] = i + 1;
for (int j = 0;j < 5;j++)
{
cout << arr[i][j] << "\t\t";
}
cout << endl;
}
}
2.2 短作业优先调度算法(short job first,SJF)
SJF算法是以作业的长短来计算优先级,作业越短优先级越高,作业长短是以作业运行时间长短来衡量。SJF算法可以分别用于作业调度和进程调度,再把短作业优先调度算法用于作业调度时,它将外存的作业后背队列中选择若干个估计运行时间最短的作业,优先将他们调入内存。
缺点:
(1)必须预知作业的运行时间,但一般很难预测每个作业运行时间的长短,如果预计过低,系统就可能按估计时间终止作业的运行,但此时作业未完成,所以一般偏长估计。
(2)对长作业不利,长作业周转时间明显变长,该算法完全忽视作业等待时间,可能使作业等待时间过长,出现饥饿现象。
(3)采用SJF算法时,人机无法交互。
(4)该算法没有考虑作业的紧迫程度,所以不能保证紧迫的作业得到及时处理。
算法实现:
#include "pch.h"
#include <iostream>
using namespace std;
int main()
{
cout << "请输入进程个数:" << endl;
int processNumber;
cin >> processNumber;
double **array = new double*[processNumber];
for (int i = 0;i < processNumber;i++)//申请空间
{
array[i] = new double[5];
}
for (int i = 0;i < processNumber;i++)//初始化
{
for (int j = 1;j < 5;j++)
array[i][j] = 0;
}
double startTime = 0.0, endTime = 0.0;
cout << "请输入每个进程到达时间和执行时间:" << endl;
for (int i = 0;i < processNumber;i++) {//输入每个进程开始和运行时间
cin >> startTime >> endTime;
array[i][1] = startTime;
array[i][2] = endTime;
}
double currentTime = array[0][1];//初始化当前时间,运行第一个进程
array[0][3] = currentTime + array[0][2];
currentTime += array[0][2];//当前时间,执行完第一个进程
array[0][4] = currentTime - array[0][1];
array[0][0] = 1;
double temp = 0;
//排序
for (int i = 1;i < processNumber;i++)
{
for (int j = i + 1;j < processNumber;j++)
{
if (array[i][2] > array[j][2])
{
temp = array[i][2];
array[i][2] = array[j][2];
array[j][2] = temp;
temp = array[i][1];
array[i][1] = array[j][1];
array[j][1] = temp;
}
}
}
int count = 1;
while (count < processNumber) {
for (int i = 1;i < processNumber;i++)
{
if( (array[i][1] <=currentTime)&&(array[i][0] != 1))
{
currentTime += array[i][2];
array[i][3] = currentTime;//填入进程完成时间
array[i][4] = currentTime - array[i][1];//周转时间
count++;
array[i][0] = 1;
break;
}
}
}
for (int i = 0;i < processNumber;i++)
{
array[i][0] = i + 1;
}
cout << "进程号\t" << "开始时间\t" <<"运行时间\t"<<"完成时间\t"<<"周转时间\t"<< endl;
for (int i = 0;i < processNumber;i++)
{
for (int j = 0;j < 5;j++)
cout << array[i][j] << " \t\t";
cout << endl;
}
}
2.3 优先级调度算法和高响应比优先调度算法(Heigest Response Ratio Next,HRRN)
我们可以这样理解优先级,对于先来先服务算法,作业的等待时间就是其优先级,等待时间越长,优先级越高。对于短作业调度算法,作业所需运行时间越短优先级越高。
在批处理系统中,短作业优先算法是一种比较好的算法,其主要的不足之处是长作业 的运行得不到保证。如果我们能为每个作业引入前面所述的动态优先权,并使作业的优先 级随着等待时间的增加而以速率 a 提高,则长作业在等待一定的时间后,必然有机会分配 到处理机。该优先权的变化规律可描述为:
优先权=(要求服务时间 等待时间)/ 要求服务时间 , 由于等待时间与服务时间之和就是系统对该作业的响应时间,故该优先权又相当于响 应比 RP。据此,又可表示为:
RP=(要求服务时间 等待时间)/ 要求服务时间 = 响应时间 /要求服务时间 , 由上式可以看出:
(1) 如果作业的等待时间相同,则要求服务的时间愈短,其优先权愈高,因而该算法有 利于短作业。
(2) 当要求服务的时间相同时,作业的优先权决定于其等待时间,等待时间愈长,其优 先权愈高,因而它实现的是先来先服务。 (3) 对于长作业,作业的优先级可以随等待时间的增加而提高,当其等待时间足够长时, 其优先级便可升到很高,从而也可获得处理机。 简言之,该算法既照顾了短作业,又考虑了作业到达的先后次序,不会使长作业长期 得不到服务。因此,该算法实现了一种较好的折衷。当然,在利用该算法时,每要进行调 第三章 处理机调度与死锁 ·95· 度之前,都须先做响应比的计算,这会增加系统开销。
#include"pch.h"
#include<iostream>
using namespace std;
int main()
{
int jobNum = 0;
cout << "请输入作业数量" << endl;
cin >> jobNum;
double **arr = new double*[jobNum];
for (int i = 0;i < jobNum;i++)
{
arr[i] = new double[5];
}
for (int i = 0;i < jobNum;i++)
for (int j = 0;j < 5;j++)
arr[i][j] = 0;
double startTime = 0, runningTime = 0;
cout << "请输入开始时间和运行时间" << endl;
for (int i = 0;i < jobNum;i++)//输入时间
{
cin >> startTime >> runningTime;
arr[i][1] = startTime;
arr[i][2] = runningTime;
arr[i][0] = 0;
}
//初始化
double currentTime = arr[0][1];//初始化当前时间
arr[0][3] = arr[0][1] + arr[0][2];//完成时间
currentTime = arr[0][3];
arr[0][4] = currentTime - arr[0][1];//周转时间
cout << currentTime << endl; arr[0][0] = 1;//作为标志
int count = 1;
double priority = 0;//定义优先级
while (count < jobNum)
{
int i_job = 0;//作业记录
double maxPriority = 0;//定义最大优先级
for (int i = 1;i < jobNum ;i++)//找出优先级最大的作业
{
if ((arr[i][0] != 1) && (arr[i][1] <=currentTime)) {
priority = (currentTime - arr[i][1] + arr[i][2]) / (arr[i][2]);//求出优先级
if (maxPriority < priority) {
maxPriority = priority;
i_job = i;
}
}
}
arr[i_job][3] = arr[i_job][2]+currentTime;//记录作业完成时间
currentTime += arr[i_job][2];//运行作业保存当前时间
arr[i_job][4] = currentTime - arr[i_job][1];//记录周转时间
arr[i_job][0] = 1;
count++;
}
cout << "作业号\t" << "开始时间\t" << "运行时间\t" << "结束时间\t" << "周转时间" << "\t" << endl;
for (int i = 0;i < jobNum;i++)
{
arr[i][0] = i + 1;
cout << arr[i][0] << "\t\t" << arr[i][1] << "\t\t" << arr[i][2] << "\t\t" << arr[i][3] << "\t\t" << arr[i][4] << "\t\t" << endl;
}
}