目录
一、实验目的(目的与任务)
目的:了解并掌握作业调度的功能,熟悉并掌握各种作业调度算法。
任务:模拟实现先来先服务调度算法(FCFS)或者短作业优先调度算法(SJF)。
二、实验内容(内容、要求与安排方式)
实验学时:2 实验类型:综合型
1.实验内容与要求:
(1)实验内容
模拟实现SJF调度。
设置作业体:作业名,作业的到达时间,服务时间,作业状态(W——等待,R——运行,F——完成),作业间的链接指针;
作业初始化:由用户输入作业名、服务时间、到达时间进行初始化,同时,初始化作业的状态为W。
显示函数:在作业调度前、调度中和调度后进行显示。
排序函数:对等待状态的作业按照调度算法排序(不同的调度算法排序方式不同),注意考虑到达时间。
调度函数:每次从等待队列队首调度已到达的适合的作业执行,状态变化。当服务结束时,状态变为F。
删除函数:撤销状态为F的作业。
(2)实验要求
①测试数据可以随即输入或从文件中读入;
②必须要考虑到作业的到达时间;
③最终能够计算每一个作业的周转时间、带权周转时间。
2.实验安排方式:
上机。
3.实验设备
1.所用设备:装有C/C++/JAVA等编程环境的计算机。
2.消耗性器材:无。
三、实验代码
①首先需要定义一个作业结构体
struct process
{
string pid; //作业名(作业号)
double come_time; //到达时
double run_time; //运行时
double begin_time; //开始时
double over_time; //完成时
double round_time; //周转时
double avg_time; //带权周转时
double HRR; //响应比
} pc[MAXSIZE]; //作业数
②编写排序算法
bool CmpByComeTime(process p1, process p2) // 按到达时间正序排序
{
return p1.come_time < p2.come_time;
}
bool CmpByPid(process p1, process p2) // 按id号正序排序
{
return p1.pid < p2.pid;
}
bool CmpByRunTime(process p1, process p2) // 按运行时长正序排序
{
return p1.run_time == p2.run_time ? p1.come_time < p2.come_time : p1.run_time < p2.run_time;
}
bool CmpByHRR(process p1, process p2) // 按响应比逆序排序
{
return p1.HRR > p2.HRR;
}
③计算作业的各个时间值
- 完成时间=开始时间+服务时间
- 周转时间=完成时间-到达时间
- 带权周转时间=周转时间/服务时间
void get_beginAndOver_time() // 计算作业的开始时间与完成时间
{
for (int i = 0; i < number; i++)
{
if (i == 0)
{
pc[i].begin_time = pc[i].come_time; // 第一个作业的开始时即为其到达时
}
else
{
pc[i].begin_time = pc[i - 1].over_time; // 否则后一作业的开始时为前一个作业的完成时
}
pc[i].over_time = pc[i].begin_time + pc[i].run_time; // 作业完成时 = 开始时间 + 运行时间
}
}
void get_roundAndAvg_time() // 计算作业的周转时间与带权周转时间
{
for (int i = 0; i < number; ++i)
{
pc[i].round_time = pc[i].over_time - pc[i].come_time; // 周转时 = 完成时间 - 到达时间
pc[i].avg_time = pc[i].round_time * 1.0 / pc[i].run_time; // 平均周转时 = 周转时间 / 运行时间
}
}
④FCFS与SJF的具体实现
void FCFS()
{
sort(pc, pc + number, CmpByComeTime);
get_beginAndOver_time();
get_roundAndAvg_time();
}
void SJF()
{
sort(pc, pc + number, CmpByComeTime); // 先按到达时排序
sort(pc + 1, pc + number, CmpByRunTime); // 再按运行时排序
get_beginAndOver_time();
get_roundAndAvg_time();
}
⑤编写函数,打印输出作业的各个时间值
void printResult() // 打印输出作业的各个时间值
{
cout << "执行顺序:"; // << endl
for (int i = 0; i < number; ++i)
{
/* code */
cout << pc[i].pid << " ";
}
cout << endl;
cout << "作业名" << '\t' << "到达时" << '\t' << "运行时" << '\t'
<< "开始时" << '\t' << "完成时" << '\t' << "周转时" << '\t'
<< "带权周转时" << '\t' << endl;
sort(pc, pc + number, CmpByPid);
double sum_round_time = 0.0;
double avg_sum_round_time = 0.0;
double sum_avg_time = 0.0;
double avg_sum_avg_time = 0.0;
for (int i = 0; i < number; ++i)
{
sum_round_time += pc[i].round_time;
sum_avg_time += pc[i].avg_time;
cout << pc[i].pid << '\t' << pc[i].come_time << '\t'
<< pc[i].run_time << '\t' << pc[i].begin_time << '\t'
<< pc[i].over_time << '\t' << pc[i].round_time << '\t'
<< pc[i].avg_time << endl;
}
avg_sum_round_time = sum_round_time * 1.0 / number;
avg_sum_avg_time = sum_avg_time * 1.0 / number;
cout << "平均周转时间: " << avg_sum_round_time << endl
<< "平均带权周转时间: " << avg_sum_avg_time << endl;
}
完整实验代码
#include <iostream>
#include <algorithm>
using namespace std;
#define MAXSIZE 5 // 作业数
int number; // 用户输入的进程数量
struct process
{
string pid; //作业名(作业号)
double come_time; //到达时
double run_time; //运行时
double begin_time; //开始时
double over_time; //完成时
double round_time; //周转时
double avg_time; //带权周转时
double HRR; //响应比
} pc[MAXSIZE]; //作业数
bool CmpByComeTime(process p1, process p2) // 按到达时间正序排序
{
return p1.come_time < p2.come_time;
}
bool CmpByPid(process p1, process p2) // 按id号正序排序
{
return p1.pid < p2.pid;
}
bool CmpByRunTime(process p1, process p2) // 按运行时长正序排序
{
return p1.run_time == p2.run_time ? p1.come_time < p2.come_time : p1.run_time < p2.run_time;
}
bool CmpByHRR(process p1, process p2) // 按响应比逆序排序
{
return p1.HRR > p2.HRR;
}
void get_beginAndOver_time() // 计算作业的开始时间与完成时间
{
for (int i = 0; i < number; i++)
{
if (i == 0)
{
pc[i].begin_time = pc[i].come_time; // 第一个作业的开始时即为其到达时
}
else
{
pc[i].begin_time = pc[i - 1].over_time; // 否则后一作业的开始时为前一个作业的完成时
}
pc[i].over_time = pc[i].begin_time + pc[i].run_time; // 作业完成时 = 开始时间 + 运行时间
}
}
void get_roundAndAvg_time() // 计算作业的周转时间与带权周转时间
{
for (int i = 0; i < number; ++i)
{
pc[i].round_time = pc[i].over_time - pc[i].come_time; // 周转时 = 完成时间 - 到达时间
pc[i].avg_time = pc[i].round_time * 1.0 / pc[i].run_time; // 平均周转时 = 周转时间 / 运行时间
}
}
void get_HRR(int beg) // 计算作业的响应比
{
for (int i = beg; i < number; i++)
{
pc[i].HRR = (pc[beg - 1].over_time - pc[i].come_time) * 1.0 / pc[i].run_time;
}
}
void FCFS() // FCFS(first come first served):先来先服务,根据到达时间依次执行
{
sort(pc, pc + number, CmpByComeTime);
get_beginAndOver_time();
get_roundAndAvg_time();
}
void SJF() // SJF(short job first):根据作业的运行时间从小到大依次执行
{
sort(pc, pc + number, CmpByComeTime); // 先按到达时排序
sort(pc + 1, pc + number, CmpByRunTime); // 再按运行时排序
get_beginAndOver_time();
get_roundAndAvg_time();
}
void HRRN() // HRRN(highest response ratio next):根据响应比从大到小依次执行,响应比动态计算
{
sort(pc, pc + number, CmpByComeTime); // 先按到达时排序
for (int i = 1; i < number; ++i)
{
get_HRR(i);
sort(pc + i, pc + number, CmpByHRR);
}
get_beginAndOver_time();
get_roundAndAvg_time();
}
void printResult() // 打印输出作业的各个时间值
{
cout << "执行顺序:"; // << endl
for (int i = 0; i < number; ++i)
{
/* code */
cout << pc[i].pid << " ";
}
cout << endl;
cout << "作业名" << '\t' << "到达时" << '\t' << "运行时" << '\t'
<< "开始时" << '\t' << "完成时" << '\t' << "周转时" << '\t'
<< "带权周转时" << '\t' << endl;
sort(pc, pc + number, CmpByPid);
double sum_round_time = 0.0;
double avg_sum_round_time = 0.0; // 平均周转时间
double sum_avg_time = 0.0;
double avg_sum_avg_time = 0.0; // 平均带权周转时间
for (int i = 0; i < number; ++i)
{
sum_round_time += pc[i].round_time;
sum_avg_time += pc[i].avg_time;
cout << pc[i].pid << '\t' << pc[i].come_time << '\t'
<< pc[i].run_time << '\t' << pc[i].begin_time << '\t'
<< pc[i].over_time << '\t' << pc[i].round_time << '\t'
<< pc[i].avg_time << endl;
}
avg_sum_round_time = sum_round_time * 1.0 / number;
avg_sum_avg_time = sum_avg_time * 1.0 / number;
cout << "平均周转时间: " << avg_sum_round_time << endl
<< "平均带权周转时间: " << avg_sum_avg_time << endl;
}
int main() // 入口函数
{
cout << "请输入进程个数:";
cin >> number;
cout << endl;
cout << "请分别输入进程的名称、到达时间、服务时间:" << endl;
for (int i = 0; i < number; i++)
{
cin >> pc[i].pid >> pc[i].come_time >> pc[i].run_time;
}
cout << endl;
FCFS();
cout << "the results of FCFS are:" << endl;
printResult();
cout << endl;
SJF();
cout << "the results of SJF are:" << endl;
printResult();
cout << endl;
HRRN();
cout << "the results of HRRN are:" << endl;
printResult();
cout << endl;
system("pause");
return 0;
}
将程序打包为exe文件
codeblocks下 写程序,先要建立一个工程。写好程序后,选择Build(构建),在工程目录里面就有个Debug或者Release的文件夹,里面就是打包好的exe文件。
四、实验结果
输入作业的个数,然后分别输入进程的名称、到达时间、服务时间,对程序进行测试。
测试样例1
测试样例2
五、实验总结
通过此次实验,对进程的常用算法有了更深的理解,知道了FCFS/SJF进程调度算法的实现过程和程序编写。对作业的完成时间、周转时间、带权周转时间等计算掌握地更加熟练。实验中,将理论和实践相结合,对操作系统的学习更加深入。
FCFS(first come first served):先来先服务,根据到达时间依次执行。
SJF(short job first):根据作业的运行时间从小到大依次执行。
HRRN(highest response ratio next):根据响应比从大到小依次执行,响应比动态计算。
周转时间 = 完成时间 - 到达时间
带权周转时间 = 周转时间 / 运行时间
响应比 = (运行时间+已经等待时间) / 运行时间 = 1+已经等待时间 / 运行时间【响应比可能表达方法不同,但是意义是一样的。】