一、实验内容
1、使用优先数调度算法完成进程的调度
1) 采用动态优先数法确定进程的优先级别。
2) 设计三个链队列,分别用来表示运行队列、就绪队列和完成队列。
3) 用户输入进程标识符以及进程所需要的时间,申请空间存放进程 PCB 信息。
优先数调度算法为每个进程设一个优先数,它总是把处理机分配给就绪队列中具有最高优先权 的进程。常用的算法有静态优先数法和动态优先数法。
动态优先数法使进程的优先权随时间而改变。初始的进程优先数取决于进程运行所需要的时 间,时间长则优先数低。可采取将进程优先数定为一个较大的数(比如 50)减去进程运行所需要 的时间。
随着进程的运行对优先数进行调整,每次运行时都是从就绪队列中选取优先数最大的进程运 行。以一个时间片为固定周期 T,每个周期动态调整各个进程的优先级,当前正在执行的进程优先 级降低(优先数减小),所有就绪进程优先级提升(优先数增加),每个时间片开始时,重新选择当 前优先级最高的进程投入运行。如果进程所需时间为 0,说明进程运行完毕,将其状态变为完成状 态“F”,将此进程 PCB 插入到完成队列中。重复上述过程,直到就绪队列为空,所有进程都变为 完成状态为止。
(2)使用时间片轮转算法完成进程的调度
时间片轮转调度:具体做法是调度程序每次把 CPU 分配给当前最高优先级进程使用一个时间 片。当这个时间片结束时,强迫该进程让出处理器,进行下一轮优先级调度,直至就绪队列中所有 进程都运行完成为止。实现这种调度要使用一个间隔时钟。当一个进程开始运行时,就将时间片的 值置入间隔时钟内,当发生间隔时钟中断时,就表明该进程连续运行的时间已超过一个规定的时间 片。此时,中断处理程序就通知处理器调度进行处理器的切换工作
二、实验效果
本次实验用到的主要结构体、队列以及函数有:进程控制块(PCB)、进程表(用链表实现,链表头指针为pcb)、就绪队列(ready)、完成队列(finish)、执行队列(execute,由于只有一个处理器,所以并没有真正设置执行队列)、获取进程信息函数(用于获取进程的标识符和cpu时间)、可视化函数、静态优先权执行函数、动态优先权执行函数、时间片轮转法执行函数、人机交互函数。
本次实验的特点是实现了静态优先权调度、动态优先权调度、时间片轮转法调度、可视化。
可视化是利用#include<windows.h>文件里面的系统调用函数system(“cls”)、字符和#include<time>文件里面的系统调用函数Sleep(time)相互配合实现字符形式的可视化。system(“cls”)的功能是清屏。即清楚上一次的打印输出,再搭配Sleep(“cls”),利用人眼的钝感,就实现了动态的可视化效果。
三、实验结果
由于本实验实现了动态可视化,因此只能截取进程调度过程中某一时刻的截图。
1、人机交互
本实验采用测试用例如下:
测试用例1:
p1 2
p2 2
p3 3
p4 6
p5 9
测试用例2:(改测试用例考虑一些非法的值,用于检验处理器的稳定性)
p1 2
p2 0
p3 9
p4 0
p5 0
2、静态优先权调度
2.1 测试用例1
可以看出调度算法按优先级依次执行所有进程。
2.2 测试用例2
可以看出,当遇到非法值时,也不会影响处理机的运行。
3、动态优先权调度
3.1 测试用例1
本次实验时间片设置为2,因此第一次调度优先级最高的进程p1时p1就可以执行完成,接下来从就绪队列中调度优先级最高的进程。
从上图进程p4、p5在占用cpu时,在固定的时间片time_slice=2结束时当前执行进程的优先数较小,优先级可能降低。也即实现了动态优先权调度。
3.2 测试用例2
从上图可以看出,当遇到非法值时,动态优先权调度也可以实现调度,具有比较好的稳定性。
4、时间片轮转法调度
4.1 测试用例1
从运行结果可以看出,时间片轮转算法是按照进程的优先级从高到低依次给每个进程一个时间片time_slace=2。
4.2 测试用例2
从上图截取的两个时刻的运行状态可以明显看出时间片轮转调度算法的特点,即公平性,同时也可以看出时间片轮转算法对于非法值也具有比较好的稳定性。
四、实验代码
#include<iostream>
#include<string>
#include<windows.h>
#include<time.h>
#include<queue>
#include<algorithm>
#define P_NUM 5
#define P_TIME 50
#define MAXINT 0x3f3f3f3f
using namespace std;
struct PCB {
string name;//进程标识符
int prio;//优先数
int round;//时间片
int cputime;//cpu时间
int needtime;//进程所需要的cpu时间
int count;//计数器
char state;//进程状态
struct PCB* next;//进程链表指针
PCB() {//构造函数
this->name = "";
this->prio = 0;
this->round = 0;
this->cputime = 0;
this->needtime = 0;
this->count = 0;
this->state = 'R';
this->next = NULL;
}
};
PCB* pcb = NULL;//进程表
int time_slice = 2;//时间片
deque <PCB*> ready;//就绪队列
deque <PCB*> finish;//完成队列
deque <PCB*>::iterator it;//队列迭代器
//用于双向队列ready排序,优先级高的排在双向队列的前面
bool cmp(PCB* x, PCB* y) {
if (x->prio > y->prio)return true;
else return false;
}
//用于初始化ready双向队列
void init(PCB* p) {
while (p) {
ready.push_back(p);
p = p->next;
}
}
//获取进程信息,即进程标识符和cpu时间,以及初始化进程的优先级
PCB* get_process() {
PCB* p1 = NULL, * p2 = NULL;//p1、p2协同构建进程表
cout << "请输入进程的标识符和所需要的cpu时间" << endl;
for (int i = 0; i < P_NUM; i++) {
p1 = new PCB();
cin >> p1->name >> p1->needtime;
p1->prio = P_TIME - p1->needtime;//计算优先数
p1->round = time_slice;//初始化时间片
if (i == 0) {
pcb = p1;
p2 = p1;
}
else {
p2->next = p1;
p2 = p1;
}
}
return pcb;
}
//可视化
void display() {
cout << "name" << "\t" << "cputime" << "\t" << "needtime" << "\t" << "prio" << "\t" << "state" << endl;
for (it = ready.begin(); it != ready.end(); it++) {
cout << (*it)->name << "\t" << (*it)->cputime << "\t" << (*it)->needtime << "\t\t" << (*it)->prio << "\t";
switch ((*it)->state) {
case 'R':cout << "ready" << endl; break;
case 'E':cout << "execute" << endl; break;
case 'F':cout << "finish" << endl; break;
}
}
for (it = finish.begin(); it != finish.end(); it++) {
cout << (*it)->name << "\t" << (*it)->cputime << "\t" << (*it)->needtime << "\t\t" << (*it)->prio << "\t";
switch ((*it)->state) {
case 'R':cout << "ready" << endl; break;
case 'E':cout << "execute" << endl; break;
case 'F':cout << "finish" << endl; break;
}
}
Sleep(1000);
}
//静态优先权法执行
void cpuexe1() {
PCB* p_option = NULL;
sort(ready.begin(), ready.end(), cmp);
p_option = ready.front();
p_option->state = 'E';
while (p_option->needtime > 0) {
system("cls");
display();
p_option->needtime--;
p_option->cputime++;
}
ready.pop_front();
if (p_option->needtime == 0) {
p_option->state = 'F';
finish.push_back(p_option);
}
else {
p_option->state = 'R';
ready.push_back(p_option);
}
}
//动态优先权法执行
void cpuexe2() {
PCB* p_option = NULL;
sort(ready.begin(), ready.end(), cmp);
p_option = ready.front();
p_option->state = 'E';
while (p_option->count < p_option->round) {
if (p_option->needtime == 0) {//非法
break;
}
p_option->count++;
system("cls");
display();
p_option->needtime--;
p_option->cputime++;
if (p_option->needtime == 0) {//进程已经执行完成
break;
}
}
p_option->prio -= 3;//固定时间片结束后,当前执行的进程的优先数减小,就绪队列进程的优先数相对增大
p_option->count = 0;//计数器归零
ready.pop_front();
if (p_option->needtime == 0) {
p_option->state = 'F';
finish.push_back(p_option);
}
else {
p_option->state = 'R';
ready.push_back(p_option);
}
}
//时间片轮转法执行
void cpuexe3() {
sort(ready.begin(), ready.end(), cmp);
int num = ready.size();//就绪队列中有多少进程,按优先级先后给每个进程一个时间片
for (int i = 1; i <= num; i++) {
PCB* p = ready.front();
p->state = 'E';
while (p->count < p->round) {
if (p->needtime == 0) {//非法
break;
}
p->count++;
system("cls");
display();
p->needtime--;
p->cputime++;
if (p->needtime == 0) {//进程已经执行完成
break;
}
}
ready.pop_front();
p->count = 0;
if (p->needtime == 0) {
p->state = 'F';
finish.push_back(p);
}
else {
p->state = 'R';
ready.push_back(p);
}
}
}
//人机交互函数
void solve() {
int op, op1;
cout << "请选择算法,输入1表示优先数调度算法,输入2表示时间片轮转法:";
cin >> op;
if (op == 1) {
cout << "输入1表示静态优先权法,输入2表示动态优先权法:";
cin >> op1;
if (op1 == 1) {//执行静态优先权法
while (!ready.empty()) {
cpuexe1();
}
system("cls");
display();
}
else if (op1 == 2) {//执行动态优先权法
while (!ready.empty()) {
cpuexe2();
}
system("cls");
display();
}
}
else if (op == 2) {//执行时间片轮转法
while (!ready.empty()) {
cpuexe3();
}
system("cls");
display();
}
}
int main() {
pcb = get_process();
init(pcb);
solve();
return 0;
}