实验原理:
设计一个按优先数调度算法实现处理器调度的程序。
(1) 假定系统有五个进程,每一个进程用一个进程控制块PCB来代表,进程控制块的格式为:
其中,进程名——作为进程的标识,假设五个进程的进程名分别为P1,P2,P3,P4,P5。
指针——按优先数的大小把五个进程连成队列,用指针指出下一个进程的进程控制块的首地址,最后一个进程中的指针为“0”。
要求运行时间——假设进程需要运行的单位时间数。
优先数——赋予进程的优先数,调度时总是选取优先数大的进程先执行。
状态——可假设有两种状态,“就绪”状态和“结束”状态。五个进程的初始状态都为“就绪”,用“R”表示,当一个进程运行结束后,它的状态为“结束”,用“E”表示。
(2) 在每次运行你所设计的处理器调度程序之前,为每个进程任意确定它的“优先数”和“要求运行时间”。
(3) 为了调度方便,把五个进程按给定的优先数从大到小连成队列。用一单元指出队首进程,用指针指出队列的连接情况。例:
队首标志
K2
(4) 处理器调度总是选队首进程运行。采用动态改变优先数的办法,进程每运行一次优先数就减“1”。由于本实验是模拟处理器调度,所以,对被选中的进程并不实际的启动运行,而是执行:
- :优先数-1 要求运行时间-1
来模拟进程的一次运行。
提醒注意的是:在实际的系统中,当一个进程被选中运行时,必须恢复进程的现场,让它占有处理器运行,直到出现等待事件或运行结束。在这里省去了这些工作。
(5) 进程运行一次后,若要求运行时间0,则再将它加入队列(按优先数大小插入,且置队首标志);若要求运行时间=0,则把它的状态修改成“结束”(E),且退出队列。
(6) 若“就绪”状态的进程队列不为空,则重复上面(4)和(5)的步骤,直到所有进程都成为“结束”状态。
(7) 在所设计的程序中应有显示或打印语句,能显示或打印每次被选中进程的进程名以及运行一次后进程队列的变化。
(8) 为五个进程任意确定一组“优先数”和“要求运行时间”,启动所设计的处理器调度程序,显示或打印逐次被选中进程的进程名以及进程控制块的动态变化过程。
算法流程图:
代码演示(附带详细注释):
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdbool.h>
#define PNUM 5
static int arr[PNUM] = { 0 };//定义全局数组储存优先数
int count = 1;//记录运行次数
typedef struct PCB {
char name[2];
int time;
int preNumber;
char z;
PCB* next;
}PCB;
//初始化
PCB* initPCB() {
PCB* head = NULL, * tail = NULL;
srand(time(0));
for (int i = 0;i < PNUM;++i) {
PCB* p = (PCB*)malloc(sizeof(PCB));
printf("请输入第%d个进程的名字:\n", i + 1);
char str[5];
scanf("%s", str);
strcpy(p->name, str);//结构体中的字符串赋值方式 切记 自己容易忘
p->time = rand() % 6 + 1;//随机生成要求运行时间1~6
p->preNumber = rand() % 5 + 1;随机生成优先数1~5
arr[i] = p->preNumber;
p->z = 'R';
//按照创建顺序将P1~P5连接起来
if (head == NULL) {
head = p;
tail = p;
tail->next = NULL;
}
else {
tail->next = p;
tail = p;
tail->next = NULL;
}
}
return head;
}
//打印
void printPCB(PCB* head) {
PCB* p = head;
printf("--------------------------------------\n");
printf("进程名 要求运行时间 优先数 状态\n");
for (int i = 0;i < PNUM;++i) {
printf(" %c%c\t\t%d\t %d\t %c\n", p->name[0], p->name[1], p->time, p->preNumber, p->z);
p = p->next;
}
printf("--------------------------------------\n");
}
//对优先数进行冒泡排序
void sort(int arr[]) {
for (int i = 0;i < PNUM - 1;++i) {
int flag = 0;
int j;
for (j = 0;j < PNUM - 1 - i;++j) {
if (arr[j] < arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
flag = 1;
}
}
if (flag == 0)
break;
}
}
//找到最大优先数的PCB对应的指针返回
PCB* findMax(PCB* head, int max) {
PCB* p = head;
while (p) {
if (p->preNumber == max) {
return p;
}
p = p->next;
}
return NULL;
}
//运行一次
//运行结束时 定义优先数变为负一 要求运行时间变为0 状态变为'E'
void run(PCB* r, int arr[]) {
//1.若优先数和要求运行时间都不为0 则运行时间-1 优先数-1
if (r->time != 0 && r->preNumber != 0) {
r->time--;
r->preNumber--;
arr[0]--;//数组里面储存的是优先数 也执行-1操作
}
//2.若要求运行时间不等于零 而优先数已经为0 则只优先数-1
else if (r->time != 0 && r->preNumber == 0) {
r->time--;
}
//3.若要求运行时间为零 优先数不为零 但程序已经不需要运行了
else if (r->time == 0 && r->preNumber != 0) {
r->preNumber = -1;//优先数置为负一
arr[0] = -1;
r->z = 'E';
}
//4.若要求运行时间与优先数同时为零
else if (r->time == 0 && r->preNumber == 0) {
r->preNumber = -1;
arr[0] = -1;
r->z = 'E';
}
//1、2操作若要求时间变为0时 进行此操作
if (r->time == 0) {
r->preNumber = -1;
arr[0] = -1;
r->z = 'E';
}
}
//检查结果 若状态全为E 则结束
bool checkResult(PCB* head) {
PCB* p = head;
while (p) {
if (p->z == 'R')
return false;
else
p = p->next;
}
return true;
}
void start(PCB* head) {
while (1) {
//排序
sort(arr);
//查找并返回最大优先数对应的指针
PCB* r = findMax(head, arr[0]);
//进行一次运行
run(r, arr);
//打印此次进程运行结果
printf("%c%c正在运行......\n", r->name[0], r->name[1]);
printf("第%d次运行结果:\n", count++);
printPCB(head);
printf("\n");
//检查运行结果
bool result = checkResult(head);
if (result) {
break;
}
}
}
int main() {
//初始化五个进程//并连接起来
PCB* head = initPCB();
//打印进程
printf("初始进程:\n");
printPCB(head);
//开始执行处理机调度
start(head);
return 0;
}
运行展示:
ps:头一回自己写比较长的代码,若有写的不好的地方,恳请指正,希望对你有所帮助,谢谢!