目的
通过模拟操作系统任务调度原理的实现,加深对操作系统工作原理和操作系统实现方法的理解。
具体要求如下:
- 采取模块化方式进行程序设计,要求程序的功能设计、数据结构设计及整体结构设计合理。也可根据自己对题目的理解增加新的功能模块。
- 系统以菜单界面方式(至少采用文本菜单界面,如能采用图形菜单界面更好)工作,运行界面友好,演示程序以用户和计算机的对话方式进行。
- 程序算法说明清晰,理论分析与计算正确,运行情况良好,实验测试数据无误,容错性强(能对错误输入进行判断控制)。
- 编程风格良好(包括缩进、空行、适当注释、变量名和函数名见名知意,程序容易阅读等);
主要内容
某系统采用二级任务调度,第一级作业调度采用高响应比优先策略,第二级进程调度采用时间片轮转策略。假设内存最多容纳M个进程,进程不会发生阻塞,也不会被挂起。
(1)输入各个进程的进入时间和运行时间。
(2)计算各个进程的开始时间、结束时间、周转时间、带权周转时间,并直观输出显示。
(3)使用一个日志文件记录具体的调度信息。
概要设计
1.系统采用二级任务调度,第一级作业调度采用高响应比优先策略,第二级进程调度采用时间片轮转策略。
建立作业结构体,统一作业属性,减少空间消耗,方便管理。用作业队列存储作业,利于进行调度与计算。同时也可以用于输出,提高代码空间复用性。
一级作业调度使用队列存储JCB,队头位置进行CPU运行二级调度。只需要一个队列就能同时进行作业调度与进程调度,减少时间复杂度,同时设置相应属性与函数保证队列与容器内容相同,防止调度出错,增加容错性,两个循环互不影响,不用嵌套循环,时间复杂度为O(N)。时间按时间片运行或以程序结束为标志前进,时间上比按每一分钟运行判断更快,实际运行速度远快于线性的时间复杂度。
2.二级任务调度,模块化方式进行程序设计。
创建JCB结构体,存储作业名,响应比,是否运行标志,开始时间、结束时间、周转时间、带权周转时间等,用于作业调度的计算。
使用vector容器存储,并可以用于输出结果。
响应比高者优先(HRRN)调度算法,为每个作业设置一个优先权(响应比),调度之前先计算各作业的优先权,优先数高者优先调度。
RP (响应比)= 作业周转时间 / 作业运行时间=1+作业等待时间/作业运行时间
3.使用一个日志文件记录具体的调度信息。
使用fstream头文件中相应函数与IO流控制输出与文件读写。使用ofstream读写文件,ios::out|ios::ate|ios::app控制文件读写与输出。
以ios::app打开(或者“ios::app|ios::out”),如果没有文件,那么生成空文件,如果有文件,那么在文件尾追加。
4.计算各个进程的开始时间、结束时间、周转时间、带权周转时间,并直观输出显示。
使用作业队列容器中相应的排序函数对作业进行排序。初始化数据后使用循环,计算响应比并排序。
通过参数与循环,在条件语句中对时间前进和使用不同条件对相应数据进行计算,通过控制输出格式与相应方法设置输出。
详细代码
详细设计
1、作业调度
设置作业块:
struct JCB{
string name; //作业名
int comeTime; //进入时间
int memTime; //进入内存时间
int beginTime; //开始运行时间
int serverTime; //需要运行的时间
int runTime; //已经运行的时间
int FinishTime; //完成时间
int turnAroundTime; //周转时间
bool flag; //判断是否运行过
double ResRatio; //响应比
double WeightedTurnAroundTime; //带权周转时间
};
队列作一级调度内存,初始化完成入队。
jcb[i].beginTime = -1;//开始运行时间初始化
jcb[i].ResRatio = -1;//响应比初始化
jcb[i].memTime = -1;//进入内存时间初始化
jcb[i].runTime = 0;//运行时间初始化
jcb[i].flag = 0;//入队标志初始化为0
只有当时间大于到来时间才有响应比(能入队),同时响应比为-2的也不参与计算。根据进入时间排序, 初始化完成入队。响应比控制入队,时间随循环不断增加,控制好循环与时间的关系,防止出错。
2、进程调度
时间片大于等于需要运行的时间时:
time += (q.front().serverTime-q.front().runTime);
q.front().runTime = q.front().serverTime;
q.front().FinishTime = time;
q.front().ResRatio = -2;//作业完成后响应比置为-2
upDate(jcb,q,n);//出队前赋值
q.pop();
if(q.front().beginTime == -1){
q.front().beginTime = time;
}
calResRatio(jcb,n,time);//计算响应比并排序
for(int i = 0; i < n;i++){
if(jcb[i].comeTime <= time && jcb[i].flag == 0&&
(int)q.size()<m&&jcb[i].ResRatio >= 0){
jcb[i].memTime = time;//进入内存时间等于当前时间
jcb[i].flag = 1;
q.push(jcb[i]);
}
}
finishCount++;
否则time += TimeSlice;时间按时间片正常运行,队头未运行完成JCB再进入队尾等待。
for(int i = 0; i < n;i++){
if(jcb[i].comeTime <= time && jcb[i].flag == 0&&
(int)q.size()<m&&jcb[i].ResRatio >= 0){
jcb[i].memTime = jcb[i].comeTime;//进入内存时间等于到来时间
jcb[i].flag = 1;
q.push(jcb[i]);
}
}
upDate(jcb,q,n);//出队前赋值
JCB temp = q.front();//临时保存
q.pop();//出队
if(q.front().beginTime == -1){
q.front().beginTime = time;
}
q.push(temp);//再加入队尾
}
3、结果输出
根据进入时间排序vector,将vector中数据通过#include <iomanip>控制输出与文件的输出。再把输出时间转换为24小时制。
void userGuide(){
cout<<"此系统采用二级任务调度,第一级作业调度采用高响应比优先策略,第二级进程调度采用时间片轮转策略。"<<endl;
cout<<"系统会计算各个进程的进入内存时间、开始时间、结束时间、周转时间、带权周转时间,并直观输出显示。"<<endl;
cout<<"同时系统会输出日志文件至D:\\操作系统课设\\record.txt(若无文件则自动生成)"<<endl;
cout<<"----------------------------------------------"<<endl;
}
结果打印函数:
void printResult(int hour,int min,ofstream &fileout){
//结果打印
cout<<setw(15)<<hour<<":";
fileout<<setw(18)<<hour<<":";
if(min == 0){
cout<<"00";
fileout<<"00";
}else if (min < 10) {
cout<<"0";
fileout<<"0";
cout<<min;
fileout<<min;
}else {
cout<<min;
fileout<<min;
}
主函数输出控制:
for (int i = 0; i < n;i++) {
jcb[i].turnAroundTime = jcb[i].FinishTime-jcb[i].comeTime;//周转时间
jcb[i].WeightedTurnAroundTime = jcb[i].turnAroundTime*1.0/jcb[i].serverTime;
int outTimeHour = 0,outTimeMin = 0;
cout<<setiosflags(ios::right);
fileout<<setiosflags(ios::right);
cout<<jcb[i].name;
fileout<<jcb[i].name;
//输出时间转换为24小时制
outTimeHour = jcb[i].comeTime/60;
outTimeMin = jcb[i].comeTime%60;
printResult(outTimeHour,outTimeMin,fileout);
outTimeHour = jcb[i].memTime/60;
outTimeMin = jcb[i].memTime%60;
printResult(outTimeHour,outTimeMin,fileout);
outTimeHour = jcb[i].beginTime/60;
outTimeMin = jcb[i].beginTime%60;
printResult(outTimeHour,outTimeMin,fileout);
outTimeHour = jcb[i].FinishTime/60;
outTimeMin = jcb[i].FinishTime%60;
printResult(outTimeHour,outTimeMin,fileout);
cout<<setw(15)<<jcb[i].turnAroundTime
<<setw(17)<<fixed<<setprecision(1)<<jcb[i].WeightedTurnAroundTime<<endl;
fileout<<setw(19)<<jcb[i].turnAroundTime
<<setw(18)<<fixed<<setprecision(1)<<jcb[i].WeightedTurnAroundTime<<endl;
}
结果测试
基本功能及作业调度与进程调度测试
基本功能正确运行。菜单界面正常。
高响应比作业晚到测试
内存空间设置为3测试
日志文件写入测试
用户指引
此系统采用二级任务调度,第一级作业调度采用高响应比优先策略,第二级进程调度采用时间片轮转策略。
系统会计算各个进程的进入内存时间、开始时间、结束时间、周转时间、带权周转时间,并直观输出显示。
同时系统会输出日志文件至D:\\操作系统课设\\record.txt(若无文件则自动生成)
请输入进程数:
请输入内存容量:
请输入时间片(min):
输入第1个作业名:x
输入作业x进入时间(HH:MM):
输入作业x运行时间:
附赠输入样例
//基本功能
5
2
20
A
10:00
50
B
10:20
40
C
10:30
20
D
10:40
30
E
11:00
40
//高响应比后到
5
2
20
A
10:00
50
B
10:20
40
C
10:30
200
D
10:40
10
E
11:00
40
//时间片短
5
2
5
A
8:00
40
B
8:30
30
C
8:35
30
D
8:40
20
E
9:00
40
//3个内存
5
3
20
A
10:00
50
B
10:20
40
C
10:30
20
D
10:40
30
E
11:00
40