一、实验目的
(1)掌握周转时间、等待时间、平均周转时间等概念及其计算方法。
(2)理解五种常用的进程调度算法(FCFS、SJF、HRRF、HPF、RR),区分算法之间的差异性,并用C语言模拟实现各算法。
(3)了解操作系统中高级调度、中级调度和低级调度的区别和联系。
二、实验环境
硬件环境:计算机一台,局域网环境;
软件环境:Windows或Linux操作系统,C语言编程环境。
三、实验内容和步骤
(一)实验说明
1.基本概念
程序:程序是指静态的指令集合,它不占用系统的运行资源,可以长久地保存在磁盘中。
进程:进程是指进程实体(由程序、数据和进程控制块构成)的运行过程,是系统进行资源分配和调度的一个独立单位。进程执行程序,但进程与程序之间不是一一对应的。通过多次运行,一个程序可以包含多个进程;通过调用关系,同一进程可以被多个程序包含(如一个DLL文件可以被多个程序运用)。
作业:作业由一组统一管理和操作的进程集合构成,是用户要求计算机系统完成的一项相对独立的工作。作业可以是完成了编译、链接之后的一个用户程序,也可以是各种命令构成的一个脚本。
作业调度:作业调度是在资源满足的条件下,将处于后备状态的作业调入内存,同时生成与作业相对应的进程,并为这些进程提供所需要的资源。作业调度适用于多道批处理系统中的批处理作业。根据作业控制块中的信息,检查系统是否满足作业的资源要求,只有在满足作业调度的资源需求的情况下,系统才能进行作业调度。
2. 基本调度算法
1)先来先服务(First-Come First-Served,FCFS)调度算法
先来先服务调度算法遵循按照进入后备队列的顺序进行调度的原则。该算法是一种非抢占式的算法,是到目前为止最简单的调度算法,其编码实现非常容易。该算法仅考虑了作业到达的先后顺序,而没有考虑作业的执行时间长短、作业的运行特性和作业对资源的要求。
2)短作业优先(Shortest-Job-First,SJF)调度算法
短作业优先调度算法根据作业控制块中指出的执行时间,选取执行时间最短的作业优先调度。本实验中规定,该算法是非抢占式的,即不允许立即抢占正在执行中的长进程,而是等当前作业执行完毕再进行调度。
3)响应比高者优先(HRRF)调度算法
FCFS调度算法只片面地考虑了作业的进入时间,短作业优先调度算法考虑了作业的运行时间而忽略了作业的等待时间。响应比高者优先调度算法为这两种算法的折中。响应比为作业的响应时间与作业需要执行的时间之比。作业的响应时间为作业进入系统后的等待时间与作业要求处理器处理的时间之和。
4)优先权高者优先(Highest-Priority-First,HPF)调度算法
优先权高者优先调度算法与响应比高者优先调度算法十分相似,根据作业的优先权进行作业调度,每次总是选取优先权高的作业优先调度。作业的优先权通常用一个整数表示,也叫优先数。优先数的大小与优先权的关系由系统或者用户规定。优先权高者优先调度算法综合考虑了作业执行时间和等待时间的长短、作业的缓急度,作业对外部设备的使用情况等因素,根据系统设计目标和运行环境而给定各个作业的优先权,决定作业调度的先后顺序。
本实验所选用的调度算法均默认为非抢占式调度。
实验所用的测试数据如下表所示。
本实验所用的测试数据如下表所示
表 实验测试数据
作业Id | 到达时间 | 执行时间 | 优先权 |
800 | 50 | 0 | |
2 | 815 | 30 | 1 |
3 | 830 | 25 | 2 |
4 | 835 | 20 | 2 |
5 | 845 | 15 | 2 |
6 | 700 | 10 | 1 |
7 | 820 | 5 | 0 |
作业的数据结构:
typedef struct node
{
int number; // 作业号
int reach_time;// 作业抵达时间
int need_time;// 作业的执行时间
int privilege;// 作业优先权
float excellent;// 响应比
int start_time;// 作业开始时间
int wait_time;// 等待时间
int visited;// 作业是否被访问过
bool isreached;// 作业是否已经抵达
}job;
重要函数说明
void initial_jobs()
初始化所有作业信息
void reset_jinfo()
重置所有作业信息
int findminjob(job jobs[],int count)
找到执行时间最短的作业。输入参数:所有的作业信息及待查找的作业总数,输出为执行时间最短的作业id
int findrearlyjob(job jobs[],int count)
找到达到最早的作业 输入参数:所有的作业信息及待查找的作业总数,输出参数为最早达到的作业id
void readJobdata()
//读取作业的基本信息
void FCFS()
//先来先服务算法
void SFJschdulejob(job jobs[],int count)
//短作业优先算法 输入参数:所有的作业信息及待查找的作业总数
(二)实验内容
运行程序代码
#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXJOB 50
typedef struct node
{
int number;
int reach_time;
int need_time;
int privilege;
float excellent;
int start_time;
int wait_time;
int visited;
}job;
job jobs[MAXJOB];
int quantity;
//初始化作业
void initial_jobs()
{
int i;
for (i = 0; i < MAXJOB; i++)
{
jobs[i].number = 0;
jobs[i].reach_time = 0;
jobs[i].privilege = 0;
jobs[i].excellent = 0;
jobs[i].start_time = 0;
jobs[i].wait_time = 0;
jobs[i].visited = 0;
}
quantity = 0;
}
//读取作业信息并输出
void readJobdata()
{
FILE* fp;
char fname[20];
int i;
printf("请输入作业数据文件名:\n");
scanf("%s", fname);
if ((fp = fopen(fname, "r")) == NULL)
{
printf("错误!文件打开失败,请检查\n");
}
else
{
while (!feof(fp))
{
if (fscanf(fp, "%d %d %d %d", &jobs[quantity].number, &jobs[quantity].reach_time, &jobs[quantity].need_time, &jobs[quantity].privilege) == 4)
quantity++;
}
printf("\n\n原始作业数据\n");
printf("---------------------------------------------------------------\n");
printf(" 作业ID\t\t到达时间\t执行时间\t优先权\n");
printf("---------------------------------------------------------------\n");
for (i = 0; i < quantity; i++)
{
printf(" %-8d\t%-8d\t%-8d\t%-8d\n", jobs[i].number, jobs[i].reach_time, jobs[i].need_time, jobs[i].privilege);
}
printf("---------------------------------------------------------------\n");
}
}
//重置作业信息
void reset_jinfo()
{
int i;
for (i = 0; i < MAXJOB; i++)
{
jobs[i].start_time = 0;
jobs[i].wait_time = 0;
jobs[i].visited = 0;
}
}
//找到最早到达作业,返回地址,全部到达返回-1
int findrearlyjob(job jobs[], int count)
{
int rearlyloc = -1;
int rearlyjob = -1;
for (int i = 0; i < count; i++)
{
if (rearlyloc == -1)
{
if (jobs[i].visited == 0)
{
rearlyloc = i;
rearlyjob = jobs[i].reach_time;
}
}
else if (rearlyjob > jobs[i].reach_time && jobs[i].visited == 0)
{
rearlyjob = jobs[i].reach_time;
rearlyloc = i;
}
}
return rearlyloc;
}
//查找当前current_time已到达未执行的最短作业,若无返回最早到达作业
int findminjob(job jobs[], int count, int current_time)
{
int minjob = -1;
int minloc = -1;
for (int i = 0; i < count; i++)
{
if (minloc == -1)
{
if (jobs[i].reach_time <= current_time && jobs[i].visited == 0)
{
minjob = jobs[i].need_time;
minloc = i;
}
}
else if (minjob > jobs[i].need_time && jobs[i].visited == 0 && jobs[i].reach_time <= current_time)
{
minjob = jobs[i].need_time;
minloc = i;
}
//作业执行时间一样最短,但到达时间不同
else if (minjob == jobs[i].need_time && jobs[i].visited == 0 && jobs[i].reach_time <= current_time && jobs[minloc].reach_time > jobs[i].reach_time)
{
minloc = i;
}
}
if (minloc == -1)
minloc = findrearlyjob(jobs, quantity);
return minloc;
}
//查找当前current_time已到达未执行的最优先作业
int findhighprivilegejob(job jobs[], int count, int current_time)
{
//int t;
int privilegejob = -1;
int privilegeloc = -1;
int privilege = -1;
for (int i = 0; i < count; i++)
{
if (privilegeloc == -1)
{
if (jobs[i].reach_time <= current_time && jobs[i].visited == 0)
{
privilege = jobs[i].privilege;
privilegejob = jobs[i].need_time;
privilegeloc = i;
}
}
else if (privilege < jobs[i].privilege && jobs[i].visited == 0 && jobs[i].reach_time <= current_time)
{
privilege = jobs[i].privilege;
privilegejob = jobs[i].need_time;
privilegeloc = i;
}
else if (privilege == jobs[i].privilege && jobs[i].visited == 0 && jobs[i].reach_time <= current_time && privilegejob > jobs[i].need_time)
{
privilegejob = jobs[i].need_time;
privilegeloc = i;
}
}
if (privilegeloc == -1)
privilegeloc = findrearlyjob(jobs, quantity);
return privilegeloc;
}
//查找当前current_time已到达未执行的响应比最高的作业
int findhrrfjob(job jobs[], int count, int current_time)
{
int hrrfjob = -1;
int hrrfloc = -1;
float responsejob = -1.0;
for (int i = 0; i < count; i++)
{
if (hrrfloc == -1)
{
if (jobs[i].reach_time <= current_time && jobs[i].visited == 0)
{
hrrfjob = jobs[i].need_time;
responsejob = (float)(current_time - jobs[i].reach_time + jobs[i].need_time) / jobs[i].need_time;
hrrfloc = i;
}
}
else if (responsejob < ((float)(current_time - jobs[i].reach_time + jobs[i].need_time) / jobs[i].need_time) && jobs[i].visited == 0 && jobs[i].reach_time <= current_time)
{
responsejob = (float)(current_time - jobs[i].reach_time + jobs[i].need_time) / jobs[i].need_time;
hrrfjob = jobs[i].need_time;
hrrfloc = i;
}
else if (responsejob == ((float)(current_time - jobs[i].reach_time + jobs[i].need_time) / jobs[i].need_time) && jobs[i].visited == 0 && jobs[i].reach_time <= current_time && hrrfjob > jobs[i].need_time)
{
hrrfjob = jobs[i].need_time;
hrrfloc = i;
}
}
if (hrrfloc == -1)
hrrfloc = findrearlyjob(jobs, quantity);
return hrrfloc;
}
void FCFS()
{
int i;
int current_time = 0;
int loc;
int total_waitime = 0;
int total_roundtime = 0;
loc = findrearlyjob(jobs, quantity);
printf("\n\nFCFS算法作业流\n");
printf("------------------------------------------------------------------------\n");
printf(" 作业ID\t\t到达时间\t开始时间\t等待时间\t周转时间\n");
printf("------------------------------------------------------------------------\n");
current_time = jobs[loc].reach_time;
for (i = 0; i < quantity; i++)
{
if (jobs[loc].reach_time > current_time)
{
jobs[loc].start_time = jobs[loc].reach_time;
current_time = jobs[loc].reach_time;
}
else
{
jobs[loc].start_time = current_time;
}
jobs[loc].wait_time = current_time - jobs[loc].reach_time;
printf(" %-8d\t%-8d\t%-8d\t%-8d\t%-8d\n", loc + 1, jobs[loc].reach_time, jobs[loc].start_time, jobs[loc].wait_time, jobs[loc].wait_time + jobs[loc].need_time);
jobs[loc].visited = 1;
current_time += jobs[loc].need_time;
total_waitime += jobs[loc].wait_time;
total_roundtime = total_roundtime + jobs[loc].wait_time + jobs[loc].need_time;
loc = findrearlyjob(jobs, quantity);
}
printf("------------------------------------------------------------------------\n");
printf("总等待时间:%-8d 总周转时间:%-8d\n", total_waitime, total_roundtime);
printf("平均等待时间: %4.2f 平均周转时间: %4.2f\n", (float)total_waitime / (quantity), (float)total_roundtime / (quantity));
}
void SFJschdulejob(job jobs[], int count)
{
int i;
int current_time = 0;
int loc;
int total_waitime = 0;
int total_roundtime = 0;
loc = findrearlyjob(jobs, quantity);
printf("\n\nSFJ算法作业流\n");
printf("------------------------------------------------------------------------\n");
printf(" 作业ID\t\t到达时间\t开始时间\t等待时间\t周转时间\n");
printf("------------------------------------------------------------------------\n");
current_time = jobs[loc].reach_time;
jobs[loc].start_time = jobs[loc].reach_time;
jobs[loc].wait_time = 0;
printf(" %-8d\t%-8d\t%-8d\t%-8d\t%-8d\n", loc + 1, jobs[loc].reach_time, jobs[loc].start_time, jobs[loc].wait_time, jobs[loc].wait_time + jobs[loc].need_time);
jobs[loc].visited = 1;
current_time += jobs[loc].need_time;
total_waitime = 0;
total_roundtime = jobs[loc].need_time;
loc = findminjob(jobs, quantity, current_time);
for (i = 1; i < quantity; i++)
{
if (jobs[loc].reach_time > current_time)
{
jobs[loc].start_time = jobs[loc].reach_time;
current_time = jobs[loc].reach_time;
}
else
{
jobs[loc].start_time = current_time;
}
jobs[loc].wait_time = current_time - jobs[loc].reach_time;
printf(" %-8d\t%-8d\t%-8d\t%-8d\t%-8d\n", loc + 1, jobs[loc].reach_time, jobs[loc].start_time, jobs[loc].wait_time, jobs[loc].wait_time + jobs[loc].need_time);
jobs[loc].visited = 1;
current_time += jobs[loc].need_time;
total_waitime += jobs[loc].wait_time;
total_roundtime = total_roundtime + jobs[loc].wait_time + jobs[loc].need_time;
loc = findminjob(jobs, quantity, current_time);
}
printf("------------------------------------------------------------------------\n");
printf("总等待时间:%-8d 总周转时间:%-8d\n", total_waitime, total_roundtime);
printf("平均等待时间: %4.2f 平均周转时间: %4.2f\n", (float)total_waitime / (quantity), (float)total_roundtime / (quantity));
}
void HPF(job jobs[], int count)
{
int i;
int current_time = 0;
int loc;
int total_waitime = 0;
int total_roundtime = 0;
loc = findrearlyjob(jobs, quantity);
printf("\n\nHPF算法作业流\n");
printf("------------------------------------------------------------------------\n");
printf(" 作业ID\t\t到达时间\t开始时间\t等待时间\t周转时间\n");
printf("------------------------------------------------------------------------\n");
current_time = jobs[loc].reach_time;
jobs[loc].start_time = jobs[loc].reach_time;
jobs[loc].wait_time = 0;
printf(" %-8d\t%-8d\t%-8d\t%-8d\t%-8d\n", loc + 1, jobs[loc].reach_time, jobs[loc].start_time, jobs[loc].wait_time, jobs[loc].wait_time + jobs[loc].need_time);
jobs[loc].visited = 1;
current_time += jobs[loc].need_time;
total_waitime = 0;
total_roundtime = jobs[loc].need_time;
loc = findhighprivilegejob(jobs, quantity, current_time);
for (i = 1; i < quantity; i++)
{
if (jobs[loc].reach_time > current_time)
{
jobs[loc].start_time = jobs[loc].reach_time;
current_time = jobs[loc].reach_time;
}
else
{
jobs[loc].start_time = current_time;
}
jobs[loc].wait_time = current_time - jobs[loc].reach_time;
printf(" %-8d\t%-8d\t%-8d\t%-8d\t%-8d\n", loc + 1, jobs[loc].reach_time, jobs[loc].start_time, jobs[loc].wait_time,
jobs[loc].wait_time + jobs[loc].need_time);
jobs[loc].visited = 1;
current_time += jobs[loc].need_time;
total_waitime += jobs[loc].wait_time;
total_roundtime = total_roundtime + jobs[loc].wait_time + jobs[loc].need_time;
loc = findhighprivilegejob(jobs, quantity, current_time);
}
printf("------------------------------------------------------------------------\n");
printf("总等待时间:%-8d 总周转时间:%-8d\n", total_waitime, total_roundtime);
printf("平均等待时间: %4.2f 平均周转时间: %4.2f\n", (float)total_waitime / (quantity), (float)total_roundtime / (quantity));
}
void HRRF(job jobs[], int count)
{
int i;
int current_time = 0;
int loc;
int total_waitime = 0;
int total_roundtime = 0;
loc = findrearlyjob(jobs, quantity);
printf("\n\nHRRF算法作业流\n");
printf("------------------------------------------------------------------------\n");
printf(" 作业ID\t\t到达时间\t开始时间\t等待时间\t周转时间\n");
printf("------------------------------------------------------------------------\n");
current_time = jobs[loc].reach_time;
jobs[loc].start_time = jobs[loc].reach_time;
jobs[loc].wait_time = 0;
printf(" %-8d\t%-8d\t%-8d\t%-8d\t%-8d\n", loc + 1, jobs[loc].reach_time, jobs[loc].start_time, jobs[loc].wait_time, jobs[loc].wait_time + jobs[loc].need_time);
jobs[loc].visited = 1;
current_time += jobs[loc].need_time;
total_waitime = 0;
total_roundtime = jobs[loc].need_time;
loc = findhrrfjob(jobs, quantity, current_time);
for (i = 1; i < quantity; i++)
{
if (jobs[loc].reach_time > current_time)
{
jobs[loc].start_time = jobs[loc].reach_time;
current_time = jobs[loc].reach_time;
}
else
{
jobs[loc].start_time = current_time;
}
jobs[loc].wait_time = current_time - jobs[loc].reach_time;
printf(" %-8d\t%-8d\t%-8d\t%-8d\t%-8d\n", loc + 1, jobs[loc].reach_time, jobs[loc].start_time, jobs[loc].wait_time,
jobs[loc].wait_time + jobs[loc].need_time);
jobs[loc].visited = 1;
current_time += jobs[loc].need_time;
total_waitime += jobs[loc].wait_time;
total_roundtime = total_roundtime + jobs[loc].wait_time + jobs[loc].need_time;
loc = findhrrfjob(jobs, quantity, current_time);
}
printf("------------------------------------------------------------------------\n");
printf("总等待时间:%-8d 总周转时间:%-8d\n", total_waitime, total_roundtime);
printf("平均等待时间: %4.2f 平均周转时间: %4.2f\n", (float)total_waitime / (quantity), (float)total_roundtime / (quantity));
}
int main()
{
initial_jobs();
readJobdata();
FCFS();
reset_jinfo();
SFJschdulejob(jobs, quantity);
reset_jinfo();
HPF(jobs, quantity);
reset_jinfo();
HRRF(jobs, quantity);
system("pause");
return 0;
}
(三) 实验结果
要求:
1.通过程序的打印信息来检查作业信息的读入是否正确。
正确
2.运行FCFS算法,检查其运算结果是否正确
正确
3.根据下图所示补充短作业优先代码,并计算其等待时间和周转时间。
4. 参考以上算法的实现方法,编写高响应比优先算法和优先权高者优先算法
四、实验总结
由四种算法的测试数据来看,算法思想不同,所需的等待时间和周转时间也不同。
表1 算法与等待时间、执行时间、优先级的关系
作业调度算法 | 等待时间 | 执行时间 | 优先权 |
FCFS | √ | ||
SJF | √ | ||
HRRF | √ | √ | |
HPF | √ |
由表1得出FCFS算法仅考虑作业的等待时间,等待时间长的优先考虑;SJF算法主要考虑作业的执行时间,执行时间短的优先考虑;HRRF算法同时考虑了作业的等待时间和执行时间,是FCFS和SJF算法的折中;HPF算法仅考虑作业的优先权,优先权高者先执行。
我们实验结果中可以发现对测试数据而言,并非HRRF算法的平均等待时间和平均周转时间最短。对于这组作业,SJF算法的平均等待时间和平均周转时间比 HRRF算法和HPF算法的短,说明最适合这个作业的调度算法是SJF。
由此可以得出判断算法的好坏要根据具体的作业,如果对于a作业A算法的平均等待时间和周转时间是最短的,那说明A算法是最适合a作业的调度算法。
请总结一下本次实验的收获、教训和感受,结合课本内容谈一下你对操作系统中各种作业调度算法优缺点的理解。
答:FCFS算法比较有利于长作业,而不利于短作业,有利于CPU繁忙型作业,而不利于I/O繁忙型作业。并且 用于批处理系统,不适于分时系统。
SJF算法易于实现,照顾了短进程,缩短了短进程的等待时间,体现了短进程优先原则,改善了平均周转时间和平均带权周转时间,有利于提高系统的吞吐量。但是对长进程不利,甚至会导致长进程长时间无法得到关注而使得系统整体性能下降,完全未考虑进程的急迫程度,因而不能保证紧迫性进程会被及时处理,进程的运行时间很难精确估计,进程在运行前不一定能真正做到短进程被优先调度。
HRRF算法既照顾了短作业又照顾了长作业,同时也照顾了先到达进程。但是调度之前需要计算各个进程的响应比,增加了系统开销,导致对实时进程无法做出及时反映。
HPF算法调度灵活,能适应多种调度需求。但是进程优先级的划分和确定每个进程优先级比较困难,同时抢占式调度增加了系统开销。