进程调度模拟算法《石家庄铁道大学操作系统实验》实验一

废话不多说先贴一个能运行的代码,想自己理解的直接复制粘贴就行了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(); //显示每执行一次后所有进程的状态及有关信息
	}
}

这个算法依旧没有更改输入内嵌,而且不能够更改轮转时间片的大小,而且没有降低轮转过一次的优先级

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;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值