废话不多说先贴一个能运行的代码,想自己理解的直接复制粘贴就行了QAQ
#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
//进程控制块PCB结构
typedef struct PCB {
char name[10];// 进程名称(手动输入)
int prio;// 进程优先级数
int round;// 进程每次轮转的时间片数
int cputime;//进程占用CPU的时间片数
int needtime;//进程到完成还需要的时间片数
char state;//进程状态
struct PCB* next;//链指针
}PCB;
//定义全局变量(题目要求的)
PCB* run = NULL;//当前运行进程指针
PCB* ready = NULL;//就绪队列头指针
PCB* tail = NULL;//就绪队列尾指针
PCB* finish = NULL;//完成队列头指针
//创建新进程,并将它的PCB插入就绪队列
void createPCB(){
PCB* p;
p = (PCB*)malloc(sizeof(PCB));
printf("请输入进程名和相应的needtime值:\n");
scanf("%s%d", p -> name, &p -> needtime);
p->prio = 50 - p->needtime;//优先数初值设为50-need time
p->round = 2; //将轮转时间片数设为常数2
p->cputime = 0;//累计占用CPU时间片数设为0
p->state = 'W';//初始状态设为就绪态
p->next = NULL;
if (ready == NULL) {//如果就绪队列为空,则新进程为队首和队尾
ready = p;
tail = p;
}
else {//否则,新进程进入队尾
tail->next = p;
tail = p;
}
}
//调度程序就绪队列的第一个程序投入运行,更新run指针和ready指针
void firstin() {
run = ready;//将就绪态队列的第一个进程赋给run指针
ready = ready->next;//将就绪队列的第二个进程赋给ready指针
run->state = 'R';//将run指向的进程改为执行态
}
//在优先数算法中,将未完成的PCB按优先数顺序插入到就绪队列中
void insert1(PCB*p) {
PCB* q, * r;
q = ready;
r = NULL;
while (q != NULL && q->prio >= p->prio)
{
r = q;
q = q->next;
}
if (r == NULL) {//如果插入位置为队首,则更新ready指针
ready = p;
p->next = q;
}
else {//否则插入r和q中间
r->next = p;
p->next = q;
}
}
//在轮转法中,将执行了一个时间片单位(为2),但尚未完成PCB,插到就绪队列的队尾
void insert2(PCB* p) {
if (ready == NULL) { //如果就绪队列为空,则新进程为队首和队尾
ready = p;
tail = p;
p->next = NULL;
}
else { //否则,新进程插入到队尾,并更新tail指针
tail->next = p;
tail = p;
p->next = NULL;
}
}
//显示每执行一次后所有进程的状态及有关信息
void print() {
PCB* p;
printf("name\tcputime\tneedtime\tpriority\tstate\n");
if (run != NULL) {//如果有进程在执行,则先显示它
printf("%s\t%d\t%d\t\t%d\t\t%c\n", run->name, run->cputime, run->needtime, run->prio, run->state);
}
p = ready;//从就绪队列开始遍历
while (p != NULL) {//显示所有就绪态的进程
printf("%s\t%d\t%d\t\t%d\t\t%c\n", p->name, p->cputime, p->needtime, p->prio, p->state);
p = p->next;
}
p=finish;//从完成队列头开始遍历
while (p != NULL) {//显示所有完成的进程
printf("%s\t%d\t%d\t\t%d\t\t%c\n", p->name, p->cputime, p->needtime, p->prio, p->state);
p = p->next;
}
}
//按优先数算法调度进程(默认短作业优先)
void prisch() {
PCB* p;
int i;
for (i = 0;i < 5;i++) {
createPCB();//创建5个进程,插入就绪队列中
}
printf("按优先数算法调度进程:\n");
while (ready != NULL) {//当就绪队列不为空时,循环调度
firstin();//调度就绪队列的第一个进程投入运行
run->cputime++;//执行一次后,累计占用CPU时间片数加1
run->needtime--;//执行一次后,到完成的还需要时间片数减1
run->prio--;//执行一次后,优先数减1
if (run->needtime == 0) {//进程已经完成,则将他的状态改为完成态,并插入到完成队列中
run->state = 'F';
run->next = finish;
finish = run;
run = NULL;
}
else {//如果进程尚未完成,则将它的状态改为就绪态,并按照优先数插入到就绪队列中
run->state = 'W';
insert1(run);
run = NULL;
}
print();//显示每一次执行后所有进程状态及有关信息
}
}
//按时间片轮转法调度进程
void roundsch() {
PCB* p;
int i;
for (i = 0; i < 5; i++) { //创建五个进程,并插入到就绪队列中
createPCB();
}
printf("按时间片轮转法调度进程:\n");
while (ready != NULL) {//当就绪队列不为空时,循环调度
firstin();//调度就绪队列的第一个进程投入运行
run->cputime += 2; //执行一个时间片单位(为2)后,累计占用CPU时间片数加2
run->needtime -= 2; //执行一个时间片单位(为2)后,到完成还需要的时间片数减2
if (run->needtime <= 0) {//如果进程已经完成,则将他的状态改为完成态,并插入到完成队列中
run->state = 'F';
run->next = finish;
finish = run;
run = NULL;
}
else { //如果进程尚未完成,则将它的状态改为就绪态,并插入到就绪队列的队尾
run->state = 'W';
insert2(run);
run = NULL;
}
print(); //显示每执行一次后所有进程的状态及有关信息
}
}
int main()
{
int choice;
printf("选择算法:\n");
printf("1.优先数算法:\n");
printf("2.时间片轮转算法:\n");
scanf("%d", &choice);
switch (choice)
{
case 1:
prisch();//按优先数算法调度进程
break;
case 2:
roundsch();
break;
default:
printf("输入错误!\n");
}
return 0;
}
这是我在VS2019的代码如果其他版本编译器,把第一行和第二行引用的头文件改一下就行。不会加万能头的可以评论区问一下,我再写一个教你。
下面给你一个例子帮助你度过实验报告
选择算法:
1.优先数算法:
2.时间片轮转算法:
1
请输入进程名和相应的needtime值:
c1 2
请输入进程名和相应的needtime值:
c2 3
请输入进程名和相应的needtime值:
c3 4
请输入进程名和相应的needtime值:
c4 5
请输入进程名和相应的needtime值:
c5 6
选择算法:
1.优先数算法:
2.时间片轮转算法:
2
请输入进程名和相应的needtime值:
c1 2
请输入进程名和相应的needtime值:
c2 3
请输入进程名和相应的needtime值:
c3 4
请输入进程名和相应的needtime值:
c4 4
请输入进程名和相应的needtime值:
c5 6
接下来讲解一下原理和流程
我们来拆解代码
首先主函数
int main()
{
int choice;
printf("选择算法:\n");
printf("1.优先数算法:\n");
printf("2.时间片轮转算法:\n");
scanf("%d", &choice);
switch (choice)
{
case 1:
prisch();//按优先数算法调度进程
break;
case 2:
roundsch();
break;
default:
printf("输入错误!\n");
}
return 0;
}
主函数没什么难点,主要就是要给算法一个选择的提示。
其次就是优先数调度函数
void prisch() {
PCB* p;
int i;
for (i = 0;i < 5;i++) {
createPCB();//创建5个进程,插入就绪队列中
}
printf("按优先数算法调度进程:\n");
while (ready != NULL) {//当就绪队列不为空时,循环调度
firstin();//调度就绪队列的第一个进程投入运行
run->cputime++;//执行一次后,累计占用CPU时间片数加1
run->needtime--;//执行一次后,到完成的还需要时间片数减1
run->prio--;//执行一次后,优先数减1
if (run->needtime == 0) {//进程已经完成,则将他的状态改为完成态,并插入到完成队列中
run->state = 'F';
run->next = finish;
finish = run;
run = NULL;
}
else {//如果进程尚未完成,则将它的状态改为就绪态,并按照优先数插入到就绪队列中
run->state = 'W';
insert1(run);
run = NULL;
}
print();//显示每一次执行后所有进程状态及有关信息
}
}
我们把输入的数据输入内嵌如了函数本身,而且限制了进程个数为5,并且没有在初始化时进行优先数排序。
这里的finish链的添加是先将run改好状态后,更改指针。
时间片轮转调度算法
//按时间片轮转法调度进程
void roundsch() {
PCB* p;
int i;
for (i = 0; i < 5; i++) { //创建五个进程,并插入到就绪队列中
createPCB();
}
printf("按时间片轮转法调度进程:\n");
while (ready != NULL) {//当就绪队列不为空时,循环调度
firstin();//调度就绪队列的第一个进程投入运行
run->cputime += 2; //执行一个时间片单位(为2)后,累计占用CPU时间片数加2
run->needtime -= 2; //执行一个时间片单位(为2)后,到完成还需要的时间片数减2
if (run->needtime <= 0) {//如果进程已经完成,则将他的状态改为完成态,并插入到完成队列中
run->state = 'F';
run->next = finish;
finish = run;
run = NULL;
}
else { //如果进程尚未完成,则将它的状态改为就绪态,并插入到就绪队列的队尾
run->state = 'W';
insert2(run);
run = NULL;
}
print(); //显示每执行一次后所有进程的状态及有关信息
}
}
这个算法依旧没有更改输入内嵌,而且不能够更改轮转时间片的大小,而且没有降低轮转过一次的优先级
void print() {
PCB* p;
printf("name\tcputime\tneedtime\tpriority\tstate\n");
if (run != NULL) {//如果有进程在执行,则先显示它
printf("%s\t%d\t%d\t\t%d\t\t%c\n", run->name, run->cputime, run->needtime, run->prio, run->state);
}
p = ready;//从就绪队列开始遍历
while (p != NULL) {//显示所有就绪态的进程
printf("%s\t%d\t%d\t\t%d\t\t%c\n", p->name, p->cputime, p->needtime, p->prio, p->state);
p = p->next;
}
p=finish;//从完成队列头开始遍历
while (p != NULL) {//显示所有完成的进程
printf("%s\t%d\t%d\t\t%d\t\t%c\n", p->name, p->cputime, p->needtime, p->prio, p->state);
p = p->next;
}
}
通过next指针输出三个队列的值,可能run队列根本遇不到,因为都是在至少一个时钟周期后才输出的,所以都会在将队列的进程改到就绪或者结束队列中,run队列在周期结束后不会留在其中,只有时间片轮转中可能存在,需要验证。
两个insert函数
//在优先数算法中,将未完成的PCB按优先数顺序插入到就绪队列中
void insert1(PCB*p) {
PCB* q, * r;
q = ready;
r = NULL;
while (q != NULL && q->prio >= p->prio)
{
r = q;
q = q->next;
}
if (r == NULL) {//如果插入位置为队首,则更新ready指针
ready = p;
p->next = q;
}
else {//否则插入r和q中间
r->next = p;
p->next = q;
}
}
//在轮转法中,将执行了一个时间片单位(为2),但尚未完成PCB,插到就绪队列的队尾
void insert2(PCB* p) {
if (ready == NULL) { //如果就绪队列为空,则新进程为队首和队尾
ready = p;
tail = p;
p->next = NULL;
}
else { //否则,新进程插入到队尾,并更新tail指针
tail->next = p;
tail = p;
p->next = NULL;
}
}
优先数的insert1的需要比较优先数,来插入,而时间片直接插在队尾。
//调度程序就绪队列的第一个程序投入运行,更新run指针和ready指针
void firstin() {
run = ready;//将就绪态队列的第一个进程赋给run指针
ready = ready->next;//将就绪队列的第二个进程赋给ready指针
run->state = 'R';//将run指向的进程改为执行态
}
将ready队列的第一个进程推入run队列
createPCB创建进程控制块
void createPCB(){
PCB* p;
p = (PCB*)malloc(sizeof(PCB));
printf("请输入进程名和相应的needtime值:\n");
scanf("%s%d", p -> name, &p -> needtime);
p->prio = 50 - p->needtime;//优先数初值设为50-need time
p->round = 2; //将轮转时间片数设为常数2
p->cputime = 0;//累计占用CPU时间片数设为0
p->state = 'W';//初始状态设为就绪态
p->next = NULL;
if (ready == NULL) {//如果就绪队列为空,则新进程为队首和队尾
ready = p;
tail = p;
}
else {//否则,新进程进入队尾
tail->next = p;
tail = p;
}
}