一.实验内容
选择一个调度算法,实现处理器调度。本次实验选择【按优先数调度算法】完成。
二.实验题目
设计一个按优先数调度算法实现处理器调度的进程。
[提示]:
(1) 假定系统有五个进程,每一个进程用一个进程控制块 PCB 来代表。进程控制块的格 式为:
其中,进程名----作为进程的标识,假设五个进程的进程名分别是 P1,P2,P3,P4,P5。
指针----按优先数的大小把五个进程连成队列,用指针指出下一个进程的进程控制块 首地址,最后一个进程中的指针为“0”。
要求运行时间----假设进程需要运行的单位时间数。
优先数----赋予进程的优先数,调度时总是选取优先数大的进程先执行。
状态----可假设有两种状态,“就绪”状态和“结束“状态,五个进程的初始状态都为 “就绪“状态,用“R”表示,当一个进程运行结束后,它的状态变为“结束”, 用“E”表示。
(2) 在每次运行你所设计的处理器调度程序之前,为每个进程任意确定它的“优先数” 和“要求运行时间”。
(3) 为了调度方便,把五个进程按给定的优先数从大到小连成队列,用一单元指出队首 进程,用指针指出队列的连接情况。
(4) 处理器调度总是选队首进程运行。采用动态改变优先数的办法,进程每运行一次优 先数就减“1”。由于本实验是模拟处理器调度,所以,对被选中的进程并不实际的 启动运行,而是执行:
※优先数-1
※要求运行时间-1
来模拟进程的一次运行。
提醒注意的是:在实际的系统中,当一个进程被选中运行时,必须恢复进程的现场, 它占有处理器运行,直到出现等待事件或运行结束。在这里省去了这些工作。
(5) 进程运行一次后,若要求运行时间≠0,则再将它加入队列(按优先数大小插入,且 置队首标志);若要求运行时间=0,则把它的状态修改为“结束”(E),且退出队列。
(6) 若“就绪”状态的进程队列不为空,则重复上面(4)和(5)的步骤,直到所有进 程都成为“结束”状态。
(7) 在所设计的称序中应有显示或打印语句,能显示或打印每次被选中进程的进程名以 及运行一次后进称对列的变化。
(8) 为五个进程任意确定一组“优先数”和“要求运行时间”,启动所设计的处理器调度 程序,显示或打印逐次被选中进程的进程名以及进程控制块的动态变化过程。
三.代码实现
运行前先按提示输入五块PCB的runtime(运行时间)和pri(优先数),之后程序将自动调度执行并打印每次运行后各PCB块的信息。
#include <stdio.h>
#include<string.h>
#define MAX 5 //定义最大PCB数
struct PCB {
int ID; //进程名称
int runtime;//当前进程要求运行时间
int pri;//优先等级 当两个进程pri相同时,ID小的先执行
char state;//进程当前状态 E:结束 R:就绪 r:正在执行
};
struct PCB program[MAX];
void show_all()//打印所有PCB信息
{
int i;
printf("-------------------\n");
for (i = 0; i < MAX; i++)
{
printf("ProgramID:%d\n", i);
printf("Runtime:%d\n", program[i].runtime);
printf("Pri:%d\n", program[i].pri);
printf("States:%c\n\n", program[i].state);
}
printf("-------------------\n");
}
void initPCB() //初始化各PCB进程数据
{
int i = 0;
for (i = 0; i < MAX; i++)
{
program[i].ID = i;
program[i].state = 'R';//设置当前PCB的state为就绪态
printf("请依次设置第%d块PCB的runtime和pri:",i+1);
scanf("%d%d",&program[i].runtime,&program[i].pri);
getchar();//吸收多余换行符
}
}
int find_key() //寻找当前Pri最大的PCB下标值
{
int key=0; //存储找到Pri最大的下标值
int i=0;
int max_pri=-999;//当前最大的Pri值,默认值为-999
for (i = 0; i < MAX; i++) //循环找key值
{
if (program[i].state == 'r') //正在运行
{
return -1;
}
else
{
if (program[i].pri > max_pri&&program[i].state == 'R')
{
max_pri = program[i].pri; //更新最大pri值
key = i;//保存key值用于判断
}
}
}
if (program[key].state == 'E') //key对应PCB块已执行完
{
return -1;
}
else
{
return key; //成功返回key值
}
}
void run_program() //进程运行程序
{
int t = 0;//表示需要运行的总次数
int i = 0, j = 0;
int count = 0;//计数器
for (j = 0; j < MAX; j++)
{
t = t + program[j].runtime; //计算总共需要运行的次数
}
printf("初始化后PCB块情况:\n");
show_all();
for (j = 0; j < t; j++) //控制总运行次数,总次数为t
{
while (find_key() != -1) //成功找到符合条件的Pri最大的PCB块
{
{
program[find_key()].state = 'r';//将对应PCB块的state设置为运行态r
}
for (i = 0; i < MAX; i++) //i负责控制寻找第j次运行时state为r的PCB块
{
if (program[i].state == 'r') //执行run操作--模拟进程执行
{
program[i].pri = program[i].pri - 1;
program[i].runtime = program[i].runtime - 1;
count++;
{
if (program[i].runtime == 0) //若该次运行后该PCB的runtime已为0,则置其state为F
program[i].state = 'E';
else
program[i].state = 'R';
}
printf("第%d运行后各PCB块情况:\n",count);
show_all();
}
}//for循环-i
}//while循环
}//for循环-j
}
void main()
{
initPCB(); //初始化
run_program(); //运行程序
printf("--------------------分 割 线------------------------\n");
printf("运行后各PCB状态:\n");
show_all();
system("pause");
}
四.运行结果
1.设置各PCB块的初始数据
2. 执行run_program()函数
由1.中各PCB块的runtime数值之和可知,模拟run将运行16次后结束。截取部分运行代码.
3.程序执行结束
当16次模拟run执行完后,最后一次打印各PCB块的参数时可看到,所有PCB的runtime均为0并且states均为E(end)。
五.流程图
1.find_key()函数
2.run_program()函数