湖南师范大学操作系统实验
实验二、进程调度模拟实验
一、实验目的:
本实验模拟在单处理机环境下的处理机调度,帮助理解进程调度的概念,深入了解进程控制块的功能,以及进程的创建、撤销和进程各个状态间的转换过程。
二、实验内容:
- 进程调度算法:采用最高优先数优先的调度算法、先来先服务算法、SJF和多级反馈调度算法。
- 每个进程有一个进程控制块(PCB)表示。进程控制块可以包含如下信息:进程名、优先数、到达时间、需要运行时间、已用CPU时间、进程状态等等。进程的优先数及需要的运行时间可以事先人为输入(也可以由随机数产生)。进程的到达时间为进程输入的时间。 进程的运行时间以时间片为单位进行计算。
- 就绪进程获得CPU后都只能运行一个时间片。用已占用CPU时间加1来表示。如果运行一个时间片后,进程的已占用CPU时间已达到所需要的运行时间,则撤消该进程,如果运行一个时间片后进程的已占用CPU时间还未达所需要的运行时间,也就是进程还需要继续运行,此时应将进程的优先数减1(即降低一级),然后把它插入就绪队列等待CPU。
- 每个进程的状态可以是就绪W(Wait)、运行R(Run)、或完成F(Finish)三种状态之一。
三、实验要求: - 每进行一次调度程序都打印一次运行进程、就绪队列、以及各个进程的PCB,以便进行检查。
- 对同一组进程的各种调度算法分别计算平均周转时间和平均带权周转时间。
四、参考测试数据:
系统有5个进程,其就绪时刻、服务时间和优先级(优先级数值越大优先级越高)如下图所示。
多级反馈队列调度算法:设3个就绪队列,时间片分别为1、2、3。
湖南师范大学信息科学与工程学院实验中心
操作系统 课程实验报告
记分
计算机科学与技术专业 2019 年级 师范 班 学号 201931221026 姓名 卢泳年
指导老师 肖柳明 实验日期 2021 年 5 月 11 日
实验项目名称: 进程调度模拟实验
一、 实验目的
本实验模拟在单处理机环境下的处理机调度,帮助理解进程调度的概念,深入了解进程控制块的功能,以及进程的创建、撤销和进程各个状态间的转换过程。
二、 实验仪器
PC,vscode
三、 实验框图(电路图/流程图)
SJF与FCFS流程一致 ,只需改变队列元素的排序方式为按服务时间从小到大
MFQ多级反馈队列调度
四、 实验基本原理(原理/源程序)
代码实现
#include "iostream"
#include "queue"
#include "string"
#include "vector"
#include "algorithm"
using namespace std;
typedef struct PCB
{
string name; //进程名
int arrive; //到达时间
int need; //服务时间
int priority; //优先级
int used; //已占用CPU时间
string status; //进程状态
int finish; //完成时间
int start; //开始运行时间
float trunaround; //周转时间
float weightTurnaround; //带权周转时间
bool operator<(const PCB &a) const
{
return arrive > a.arrive;
}
} pcb;
struct cmp_need
{
bool operator()(PCB a, PCB b)
{
return a.need > b.need;
}
};
struct cmp_priority
{
bool operator()(pcb a, pcb b)
{
if (a.priority == b.priority)
return a.arrive > b.arrive;
return a.priority < b.priority;
}
};
priority_queue<pcb> p;
priority_queue<pcb, vector<pcb>, cmp_need> q;
int finish_prior;
void init()
{
pcb tmp[5] = {
{"p1", 0, 3, 2, 0, "Wait", 0, 0, 0, 0},
{"p2", 2, 6, 3, 0, "Wait", 0, 0, 0, 0},
{"p3", 4, 4, 1, 0, "Wait", 0, 0, 0, 0},
{"p4", 6, 5, 5, 0, "Wait", 0, 0, 0, 0},
{"p5", 8, 2, 4, 0, "Wait", 0, 0, 0, 0}};
p.push(tmp[0]);
p.push(tmp[1]);
p.push(tmp[2]);
p.push(tmp[3]);
p.push(tmp[4]);
}
void output(queue<pcb> &p)
{
pcb q;
cout << "进程名\t到达时间 服务时间 开始时间 已占用CPU时间 进程状态" << endl;
while (p.size() != 0)
{
q = p.front();
if (q.arrive <= finish_prior)
{
cout << q.name << "\t" << q.arrive << "\t " << q.need << "\t ";
cout << q.start << "\t " << q.used << "\t\t " << q.status << endl;
}
p.pop();
}
cout << endl << endl;
}
void output_finish(queue<pcb> &q)
{
pcb t;
float avg_trun, avg_wei_trun;
avg_trun = avg_wei_trun = 0;
int size = q.size();
cout << "所有进程执行结束之后的相关情况" << endl
<< endl;
cout << "进程名\t到达时间 服务时间 开始时间 完成时间 周转时间 带权周转时间" << endl;
while (q.size() != 0)
{
t = q.front();
cout << t.name << "\t" << t.arrive << "\t " << t.need << "\t ";
cout << t.start << "\t " << t.finish << "\t \t" << t.trunaround << "\t" << t.weightTurnaround << endl;
avg_trun += t.trunaround;
avg_wei_trun += t.weightTurnaround;
q.pop();
}
cout << "平均周转时间:" << avg_trun / size << endl;
cout << "平均带权周转时间:" << avg_wei_trun / size << endl;
cout << endl << endl;
}
void FCFS()
{
queue<pcb> temp, q;
priority_queue<pcb> tran; //用于copy p中的元素
finish_prior = 0;
pcb t;
int n = p.size();
for (int i = 0; i < n; i++)
{
t = p.top();
if (i == 0)
{
t.start = t.arrive;
}
else
{
t.start = finish_prior > t.arrive ? finish_prior : t.arrive;
}
t.finish = t.start + t.need;
t.trunaround = t.finish - t.arrive;
t.weightTurnaround = t.trunaround / t.need;
t.status = "Run";
finish_prior = t.finish;
while (t.used < t.need)
{
t.used++;
cout << "正在运行的进程" << endl;
cout << "进程名\t到达时间 服务时间 开始时间 已占用CPU时间 进程状态" << endl;
cout << t.name << "\t" << t.arrive << "\t " << t.need << "\t ";
cout << t.start << "\t " << t.used << "\t\t " << t.status << endl;
}
t.status = "Finish";
q.push(t);
p.pop();
cout << "进程" << t.name << "执行结束之后就绪队列中的进程" << endl;
tran = p;
while (!tran.empty())
{
temp.push(tran.top());
tran.pop();
}
output(temp);
}
output_finish(q);
}
void PSA()
{
finish_prior = 0;
//int current = 0;
bool flag = true; //是否为第一个进程
priority_queue<pcb, vector<pcb>, cmp_priority> q; //就绪队列
priority_queue<pcb, vector<pcb>, cmp_priority> tran; //copy q 中的元素
priority_queue<pcb> f; //已完成的进程
queue<pcb> temp; //拷贝要输出的优先级队列
pcb t;
while (!p.empty() || !q.empty())
{
cout << "第" << finish_prior + 1 << "个时间片" << endl;
t = p.top();
//此时没有可运行的进程,时间加加
while (t.arrive > finish_prior && q.empty())
{
finish_prior++;
}
while (!p.empty() && t.arrive <= finish_prior)
{ //将此时已就绪的队列放入就绪队列
q.push(t);
p.pop();
t = p.top();
}
t = q.top();
if (t.used == 0)
{
t.start = t.arrive < finish_prior ? finish_prior : t.arrive;
}
if (t.used < t.need)
{
t.status = "Run";
t.used++;
cout << "正在运行的进程" << endl;
cout << "进程名\t到达时间 服务时间 开始时间 已占用CPU时间 进程状态" << endl;
cout << t.name << "\t" << t.arrive << "\t " << t.need << "\t ";
cout << t.start << "\t " << t.used << "\t\t " << t.status << endl;
t.status = "Wait";
t.priority--;
//current++;
finish_prior++;
if (t.used == t.need)
{
t.finish = finish_prior;
//cout<< "完成时间:" << t.finish<<endl;
t.trunaround = t.finish - t.arrive;
t.weightTurnaround = t.trunaround / t.need;
t.status = "Finish";
//finish_prior = t.finish;
q.pop();
f.push(t);
}
else
{
q.pop();
q.push(t);
}
}
cout << "进程" << t.name << "执行一个时间片之后就绪队列中的进程" << endl;
if (!p.empty())
t = p.top();
//将运行完这个时间片后p中已就绪的进程添加到就绪队列
while (!p.empty() && t.arrive <= finish_prior)
{
q.push(t);
p.pop();
t = p.top();
}
tran = q;
while (!tran.empty())
{
temp.push(tran.top());
tran.pop();
}
output(temp); //打印就绪队列
}
while (!f.empty())
{
temp.push(f.top());
f.pop();
}
output_finish(temp); //打印运行完成后的队列情况
}
void SJF()
{
pcb t;
queue<pcb> temp;
priority_queue<pcb, vector<pcb>, cmp_need> tran; //copy q 中的元素
finish_prior = 0;
bool flag = true; //是否为第一个运行的进程
priority_queue<pcb> f; //运行完成后的进程队列
while (true)
{ //所有进程执行完退出
if (p.empty() && q.empty())
{
break;
}
t = p.top();
while (t.arrive > finish_prior && q.empty())
{
finish_prior++;
}
while (!p.empty() && t.arrive <= finish_prior)
{
q.push(t);
p.pop();
t = p.top();
}
t = q.top();
if (t.arrive <= finish_prior)
{
if (flag)
{ //是否是第一个进程
t.start = t.arrive;
flag = false;
}
else
{
t.start = finish_prior > t.arrive ? finish_prior : t.arrive;
}
t.finish = t.start + t.need;
t.trunaround = t.finish - t.arrive;
t.weightTurnaround = t.trunaround / t.need;
t.status = "Run";
finish_prior = t.finish;
while (t.used < t.need)
{
t.used++;
cout << "正在运行的进程" << endl;
cout << "进程名\t到达时间 服务时间 开始时间 已占用CPU时间 进程状态" << endl;
cout << t.name << "\t" << t.arrive << "\t " << t.need << "\t ";
cout << t.start << "\t " << t.used << "\t\t " << t.status << endl;
}
t.status = "Finish";
f.push(t);
q.pop();
cout << "进程" << t.name << "执行结束之后就绪队列中的进程" << endl;
if (!p.empty())
t = p.top();
while (!p.empty() && t.arrive <= finish_prior)
{
q.push(t);
p.pop();
t = p.top();
}
tran = q;
while (!tran.empty())
{
temp.push(tran.top());
tran.pop();
}
output(temp);
}
}
while (!f.empty())
{
temp.push(f.top());
f.pop();
}
output_finish(temp);
}
priority_queue<pcb> f; //已完成的进程
int cnt; //执行了几个时间片
//运行队列q size个时间片,并将该进程放入下一队列,flag判断是否是最后一个队列
void run(queue<pcb> &q, queue<pcb> &p, int size, bool flag)
{
cnt = 0;
pcb t = q.front();
if (t.used == 0)
{
t.start = finish_prior;
}
while (true)
{
size--;
cnt++;
t.used++;
finish_prior++;
t.status = "Run";
cout << "正在运行的进程" << endl;
cout << "进程名\t到达时间 服务时间 开始时间 已占用CPU时间 进程状态" << endl;
cout << t.name << "\t" << t.arrive << "\t " << t.need << "\t ";
cout << t.start << "\t " << t.used << "\t\t " << t.status << endl;
if (t.used == t.need)
{
t.finish = finish_prior;
t.trunaround = t.finish - t.arrive;
t.weightTurnaround = t.trunaround / t.need;
t.status = "Finish";
q.pop();
f.push(t);
break;
}
if (!size)
{
t.status = "Wait";
q.pop();
if (flag)
{
q.push(t);
}
else
{
p.push(t);
}
break;
}
}
}
void MFQ()
{
queue<pcb> q1, q2, q3;
queue<pcb> q; //就绪队列
queue<pcb> temp; //临时队列
finish_prior = 0;
int current = 0;
pcb t;
while (!p.empty() || !q1.empty() || !q2.empty() || !q3.empty())
{
cout << "第" << finish_prior + 1 << "个时间片" << endl;
t = p.top();
while (t.arrive > finish_prior && q1.empty() && q2.empty() && q3.empty())
{
finish_prior++;
}
//将后备队列中已就绪的进程装入
while (!p.empty() && t.arrive <= finish_prior)
{
q1.push(t);
p.pop();
t = p.top();
}
if (!q1.empty())
{
t = q1.front();
run(q1, q2, 1, false);
}
else
{
if (!q2.empty())
{
t = q2.front();
run(q2, q3, 2, false);
}
else
{
t = q3.front();
run(q3, q3, 3, true);
}
}
cout << "进程" << t.name << "执行" << cnt << "个时间片之后就绪队列中的进程" << endl;
if (!p.empty())
t = p.top();
//将运行完这个时间片后p中已就绪的进程添加到就绪队列q1
while (!p.empty() && t.arrive <= finish_prior)
{
q1.push(t);
p.pop();
t = p.top();
}
temp = q1;
cout << "第一队列" << endl;
output(temp);
temp = q2;
cout << "第二队列" << endl;
output(temp);
temp = q3;
cout << "第三队列" << endl;
output(temp);
}
while (!f.empty())
{
temp.push(f.top());
f.pop();
}
output_finish(temp); //打印运行完成后的队列情况
}
int main()
{
int menu;
init();
priority_queue<pcb> tmp = p;
do
{
cout << "==================\n菜单\n1.PSA算法\n2.FCFS算法\n3.SJF算法\n4.MFQ算法\n输入0结束程序\n==================" << endl;
cin >> menu;
switch (menu)
{
case 0:
break;
case 1:
PSA();
break;
case 2:
FCFS();
break;
case 3:
SJF();
break;
case 4:
MFQ();
break;
default:
cout << "输入错误,请重新选择操作!!!" << endl;
break;
}
p = tmp;
} while (menu != 0);
return 0;
}
测试数据
PSA算法
FCFS算法
SJF算法
MFQ多级反馈队列
心得体会
这次实验是采用最高优先数优先的调度算法、先来先服务算法、SJF和多级反馈调度算法分别进行进程的调度。比较容易实现的是最高先来先服务和SJF算法,每次都是选出相应的进程执行完再选择下一个符合条件的进程直到所有进程执行完就行了,而剩下的两个则是每运行一个时间片就要重新选择进程,在多级反馈调度算法中,需要注意的是,虽然后面的队列运行一次多个时间片,但还是要一个一个时间片递增,而不能直接加上运行的时间片,因为有可能在低优先级队列执行多个时间片的过程中,高优先级队列进入了新的就绪进程,此时需要将正在执行的进程放入当前队列的队尾,转去执行新的进程。