§2.1第二题实验目标
实验内容:进程调度。
模拟进程调度:按简单循环轮转调度算法模拟进程调度。
用一个队列模拟一系列(不少于5个)需要调度的进程,每个进程按照时间片进行处理机的分派,假设进程控制块PCB的结构如下:
进程ID
到达时间
进程响应时间
剩余时间
实验要求:
a)PCB内容自由指定,逻辑上合理即可(即不要求定义真正的时间,只要给出合理的数字即可);
b)时间片定义为:(所有进程总响应时间之和)/N2 (N为进程数);
c)在屏幕上输出以下进程状态表(表中每一行代表一个进程对一个时间片的占用):
进程ID 到达
时间 进程响应
时间 时间片
开始时间 时间片
结束时间
注意:到达时间为进程到达的时刻;进程响应时间是指一个进程预计占用CPU的总时间,不包括等待时间。这两个时间可视为初始条件(即在表中不会发生变化)。
d)要求可以通过键盘命令动态地增加进程(即增加一个PCB数据结构项),增加进程后,进程状态表内容可更新查看。
§2.2 第二题原理、方法、过程
2.2.1 设计思想
简单循环轮转调度的基本方法是当CPU空闲时,选取队首元素,赋予时间片。当该进程时间片用完时,就释放CPU控制权,进入就绪队列队尾,CPU交给下一个处于就绪队列队首元素。如下图所示:
其中,当CPU运行时,出现新的进程,则将该进程放入就绪队列,等待CPU调度,而时间片用完的进程,也可以看作一个新进程放入就绪队列进行等待。
2.2.2 程序接口设计
进程控制模块设计如下:
struct Process
{
int pos; //代表第几个输入的进程
char Process_name[50]; //进程名字,默认最长长度占用50字符
double Arrival_time; //进程到达时间
double Service_time; //服务时间 进程所需要的时间
double Start_time; //服务开始时间
double End_time; //服务结束的时间
double Turnaround_time; //周转时间 进程结束的时间-进程到达时间
}
void Init() 初始化函数,输入进程数量以及到达时间,运行时间,并且计算时间片大小
void updata() 更新就绪队列中数据,将时间片内到达的进程加入队列
void Solve_TSRA() 轮转调度算法实现
2.2.3 流程图
§2.3 第二题实验结果(关键的真实代码、截图、结果等)
2.3.1 代码展示
#include <iostream>
#include <queue>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <fstream>
using namespace std;
const int MAXN = 1000;//假设能够容纳的进程最多的个数
ifstream ifile;
struct Process
{
int pos; //代表第几个输入的进程
char Process_name[50]; //进程名字,默认最长长度占用50字符
double Arrival_time; //进程到达时间
double Service_time; //服务时间 进程所需要的时间
double Start_time; //服务开始时间
double End_time; //服务结束的时间
double Turnaround_time; //周转时间 进程结束的时间-进程到达时间
}process[MAXN];
double every_time;
int n;
queue<Process> que; //就绪队列
bool vis[MAXN]; //表示这个进程有没有在完成,完成使用true表示
bool in[MAXN]; //表示这个进程是否进队列
Process ans[MAXN]; //答案序列
double time; //计时器
int index = 0; //答案序列的指针
bool flag = false; //判断是否所有的进程都已经进队列
void Init()
{
n = 0;
ifile.open("process.txt");
if (!ifile.is_open())
{
cout << "文件打开错误" << endl;
exit(1);
}
while (!ifile.eof())
{
ifile >> process[n].Process_name >> process[n].Arrival_time >> process[n].Service_time;
process[n].pos = n;
every_time += process[n].Service_time;
n++;
}
every_time /= n * n;
every_time = ((int)(every_time * 100));
every_time = (double)every_time / 100;
cout << "时间片为" << every_time<<endl;
}
bool cmp1(const Process& a, const Process& b)
{
return a.Arrival_time < b.Arrival_time;
}
void updata()
{
int j;
for (j = 0; process[j].Arrival_time<=time && j<n; j++) //寻找下一个进程
if (!in[process[j].pos])
{
que.push(process[j]);//将时间片内到达的进程加入到队列中
in[process[j].pos] = true; //标记已经入就绪队列
}
if (j == n)
flag = true;
}
void Solve_TSRA()
{
sort(process, process + n-1, cmp1);
memset(in, false, sizeof(in));
que.push(process[0]);
in[process[0].pos] = true;
time = process[0].Arrival_time;
while (!que.empty())
{
Process temp = que.front();
que.pop();
temp.Start_time = time;
if (temp.Service_time > every_time)
{
temp.End_time = time + every_time;
temp.Service_time -= every_time;
time += every_time;
updata();
que.push(temp);
}
else
{
temp.End_time = time + temp.Service_time;
time += temp.Service_time; //这里面的时间都是有联系的,所以不用再次更新time
updata();
temp.Service_time = 0;
}
ans[index++] = temp; //将顺序存储到最终的答案序列中
if (que.empty() && !flag)
{
for (int i = 1; i < n; i++)
{
if (!in[process[i].pos])
{
que.push(process[i]);
time = process[i].Arrival_time; //更新时间
break;
}
}
}
}
printf("进程ID\t到达时间\t进程响应时间\t时间片开始时间\t时间片结束时间\n");
for (int i = 1; i < index; i++)
printf("%s\t%.2lf\t\t%.2lf\t\t%.2lf\t\t%.2lf\n", ans[i].Process_name, ans[i].Arrival_time, ans[i].End_time-ans[i].Start_time, ans[i].Start_time, ans[i].End_time);
}
int main()
{
Init();
Solve_TSRA();
return 0;
}
2.3.2 运行截图
输入的进程数据如下
运行结果如下: