动态优先权进程调度算法

题目

在这里插入图片描述

代码

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
typedef struct PCB* PCBPtr;
typedef struct PCB{
	int ID;//进程标识数
	int priority;//优先级
	int CPUTime;//进程已占用CPU时间
	int AllTime;//进程还需占用的CPU时间,运行完毕时为0
	int StartBlock;//进程的阻塞时间,表示再运行StartBlock个时间片后,进入阻塞状态
	int BlockTime;//进程被阻塞的时间,表示已阻塞的进程再等待BlockTime个时间片后将转换成就绪状态
	int State;//进程状态
	PCBPtr next;
}PCB;
typedef struct LinkQueue{
	PCBPtr front, rear;//只保存队头队尾指针
}LinkQueue;
//初始化链队
void InitQueue(LinkQueue &Q){
	Q.front = Q.rear = new PCB;//带有头结点,队头指针指向头结点,队尾指针指向队尾元素
	Q.front->State = 99;
	return;
}
//初始化PCB
PCBPtr InitPCB(PCB p){
	PCBPtr t = new PCB;
	*t = p;
	t->next = NULL;
	return t;
}
//入队
void EnQueue(LinkQueue &Q, PCB e){
	Q.rear->next = InitPCB(e);
	Q.rear = Q.rear->next;
	return;
}
//出队
bool DeQueue(LinkQueue &Q, PCB &e){
	if (Q.front == Q.rear)return false;
	PCBPtr p = Q.front->next;//p为队头元素的指针
	e = *p;
	Q.front->next = p->next;//头结点和队头元素的后导重新挂接
	if (Q.rear == p)//如果队头元素(头结点的后导)就是队尾元素(队尾指针指向)
		Q.rear = Q.front;//最后一个元素删除,队尾指针指向头结点
	delete p;
	return true;
}
//判空
bool JudgeEmpty(LinkQueue Q){
	if (Q.front == Q.rear)return true;
	return false;
}
//取队头元素
PCB GetHead(LinkQueue Q){
	return *Q.front->next;
}
int time,n,timeseg;//当前时间,进程数,时间片
//快排
void swap(PCB &a, PCB &b){
	PCBPtr A = a.next, B = b.next;
	PCB t = a;
	a = b;
	b = t;
	a.next = A;
	b.next = B;
	return;
}
PCBPtr GetPivot(PCBPtr start, PCBPtr end){
	PCBPtr p = start, q = start->next;
	PCB key = *p;
	while (1){
  		while (q->priority<=key.priority&&q != end)
			q = q->next;
		if (q->priority > key.priority&& p != end){
			p = p->next;
			swap(*p, *q);
		}
		if (q == end || p == end)
			break;
	}
	swap(*start, *p);
	return p;
}
void PrioritySort(PCBPtr start,PCBPtr end){
	if (start != end){//不止一个元素
		PCBPtr Pivot = GetPivot(start, end);
		if (Pivot)
			PrioritySort(start, Pivot);
		if (Pivot->next)
			PrioritySort(Pivot->next, end);
	}
	return;
}
void delay(int n){
	while (n--){
		for (int i = 0; i < 5; i++)
			for (int j = 0; j < 500; j++);
	}
	return;
}
//输出
void ShowTime(LinkQueue Q){
	if (JudgeEmpty(Q)){ printf("运行完毕\n"); return; }
	printf("当前时刻为:%d\n", time);
	printf("***********************各进程状态为************************\n");
	printf("ID  Priority  CPUTime  AllTime  StartBlock  BlockTime  State\n");
	Q.front = Q.front->next;
	for (int i = 0;Q.front!=NULL; i++){
		printf("%d   %d         %d        %d        %d           %d          %d\n", Q.front->ID, Q.front->priority, Q.front->CPUTime, Q.front->AllTime, Q.front->StartBlock, Q.front->BlockTime, Q.front->State);
		Q.front = Q.front->next;
	}
	return;
}
//赋予状态:0-运行,1-阻塞,2-就绪,3-结束
void SaveState(LinkQueue &Q){
	PCBPtr p = Q.front->next,f=NULL;
	bool flag = false;
	do{
		if (p->BlockTime > 0&&p->State==1){
			p->BlockTime--;
			if (p->BlockTime == 0)//阻塞变为就绪
				p->State = 2;
		}
		if (p->StartBlock > 0&&(p->State==2||p->State==0)){
			p->StartBlock--;
			if (p->StartBlock == 0)//就绪变为阻塞
				p->State = 1;
		}
		if (!flag && (p->State == 2 || p->State == 0)){//就绪队列中优先级最高的进入运行
			p->State = 0; flag = true;
		}
		else if (flag&&p->State == 0)//有运行的进程后再遇到运行状态就变回就绪状态
			p->State = 2;
		f = p;
		p = p->next;
	} while (f != Q.rear);
	return;
}
//运行状态的PCB P经历了一个时间片
void AddProject(PCBPtr &P){
	if (P->AllTime > timeseg){//未运行完
			P->priority -= 3;
			P->AllTime -= timeseg;//还需占用时间减少一个时间片
			P->CPUTime += timeseg;//已占用增加一个时间片
		}
		else{//运行完
			P->priority = 99;
			P->CPUTime += P->AllTime;
			P->AllTime = 0; P->StartBlock = 0; P->BlockTime = 0;
			P->State = 3;
		}
}
//一个时间片的时间的各个PCB的分配,状态:0-运行,1-阻塞,2-就绪,3-结束
void OpProject(LinkQueue &Q){
	if (!JudgeEmpty(Q)){
		PCBPtr p = Q.front->next,f=NULL;
		SaveState(Q);//赋予状态
		do{
			if (p->State == 0)//运行的操作
				AddProject(p);
			if (p->State == 2){//就绪优先级+1
				p->priority++;
			}
			
			f = p;
			p = p->next;
		} while (f != Q.rear);
		PrioritySort(Q.front->next, Q.rear);
		PCB t = GetHead(Q);
		if (t.State == 3)
			DeQueue(Q, t);
		ShowTime(Q);//展示
	}
	return;
}
//菜单
void menu(LinkQueue &Q){
	printf("请输入进程数:");
	scanf("%d", &n);
	printf("请设置时间片长度:");
	scanf("%d", &timeseg);
	if (n > 0){
		PCB e;
		printf("请输入各进程初始状态:状态:0-运行,1-阻塞,2-就绪,3-结束\nID  Priority  AllTime  StartBlock  BlockTime  State\n");
		e.CPUTime = 0;
		//写入
		scanf("%d %d %d %d %d %d", &e.ID, &e.priority, &e.AllTime, &e.StartBlock, &e.BlockTime,&e.State);
		EnQueue(Q, e);
		for (int i = 1; i < n; i++){
			scanf("%d %d %d %d %d %d", &e.ID, &e.priority, &e.AllTime, &e.StartBlock, &e.BlockTime, &e.State);
			e.CPUTime = 0;
			EnQueue(Q, e);
		}
	}
	//输出0时刻的进程表
	if (!JudgeEmpty(Q))//若非空,则优先级排序
		PrioritySort(Q.front->next, Q.rear);
	ShowTime(Q);
	//getchar();getchar();
	while (!JudgeEmpty(Q)){
		delay(500000);
		time+=timeseg;
		OpProject(Q);
		//getchar();
	}
	return;
}
int main(){
	LinkQueue Q;
	InitQueue(Q);
	menu(Q);
	system("pause");
	return 0;
}

1.结构体及其操作

1.0结构体

typedef struct PCB* PCBPtr;
typedef struct PCB{
	int ID;//进程标识数
	int priority;//优先级
	int CPUTime;//进程已占用CPU时间
	int AllTime;//进程还需占用的CPU时间,运行完毕时为0
	int StartBlock;//进程的阻塞时间,表示再运行StartBlock个时间片后,进入阻塞状态
	int BlockTime;//进程被阻塞的时间,表示已阻塞的进程再等待BlockTime个时间片后将转换成就绪状态
	int State;//进程状态
	PCBPtr next;
}PCB;
typedef struct LinkQueue{
	PCBPtr front, rear;//只保存队头队尾指针
}LinkQueue;

1.1初始化

//初始化链队
void InitQueue(LinkQueue &Q){
	Q.front = Q.rear = new PCB;//带有头结点,队头指针指向头结点,队尾指针指向队尾元素
	Q.front->State = 99;
	return;
}

1.2入队

//初始化PCB
PCBPtr InitPCB(PCB p){
	PCBPtr t = new PCB;
	*t = p;
	t->next = NULL;
	return t;
}
//入队
void EnQueue(LinkQueue &Q, PCB e){
	Q.rear->next = InitPCB(e);
	Q.rear = Q.rear->next;
	return;
}

1.3出队

//出队
bool DeQueue(LinkQueue &Q, PCB &e){
	if (Q.front == Q.rear)return false;
	PCBPtr p = Q.front->next;//p为队头元素的指针
	e = *p;
	Q.front->next = p->next;//头结点和队头元素的后导重新挂接
	if (Q.rear == p)//如果队头元素(头结点的后导)就是队尾元素(队尾指针指向)
		Q.rear = Q.front;//最后一个元素删除,队尾指针指向头结点
	delete p;
	return true;
}

1.4判空

//判空
bool JudgeEmpty(LinkQueue Q){
	if (Q.front == Q.rear)return true;
	return false;
}

1.5取队头元素

//取队头元素
PCB GetHead(LinkQueue Q){
	return *Q.front->next;
}

1.6快排(根据优先权)

交换值而非地址,降序
p,q之间的数是小于等于key的
p之前的数是大于key的
最后交换start和p的值,使得p作为枢纽,前面的都是大于p的,后面的都是小于等于的的

//快排
void swap(PCB &a, PCB &b){
	PCBPtr A = a.next, B = b.next;
	PCB t = a;
	a = b;
	b = t;
	a.next = A;
	b.next = B;
	return;
}
PCBPtr GetPivot(PCBPtr start, PCBPtr end){
	PCBPtr p = start, q = start->next;
	PCB key = *p;
	while (1){
  		while (q->priority<=key.priority&&q != end)
			q = q->next;
		if (q->priority > key.priority&& p != end){
			p = p->next;
			swap(*p, *q);
		}
		if (q == end || p == end)
			break;
	}
	swap(*start, *p);
	return p;
}
void PrioritySort(PCBPtr start,PCBPtr end){
	if (start != end){//不止一个元素
		PCBPtr Pivot = GetPivot(start, end);
		if (Pivot)
			PrioritySort(start, Pivot);
		if (Pivot->next)
			PrioritySort(Pivot->next, end);
	}
	return;
}

2.动态优先权算法

2.1菜单

  1. 输入,依次进队
  2. 先快排一次,并输出(时刻0)
  3. 进入无限循环直到队空结束

3.1.延时
3.2.加一个时间片的时间
3.3进入加一个时间片的各个PCB的分配子函数(里头兼有快排及输出)

//菜单
//菜单
void menu(LinkQueue &Q){
	printf("请输入进程数:");
	scanf("%d", &n);
	printf("请设置时间片长度:");
	scanf("%d", &timeseg);
	if (n > 0){
		PCB e;
		printf("请输入各进程初始状态:状态:0-运行,1-阻塞,2-就绪,3-结束\nID  Priority  AllTime  StartBlock  BlockTime  State\n");
		e.CPUTime = 0;
		//写入
		scanf("%d %d %d %d %d %d", &e.ID, &e.priority, &e.AllTime, &e.StartBlock, &e.BlockTime,&e.State);
		EnQueue(Q, e);
		for (int i = 1; i < n; i++){
			scanf("%d %d %d %d %d %d", &e.ID, &e.priority, &e.AllTime, &e.StartBlock, &e.BlockTime, &e.State);
			e.CPUTime = 0;
			EnQueue(Q, e);
		}
	}
	//输出0时刻的进程表
	if (!JudgeEmpty(Q))//若非空,则优先级排序
		PrioritySort(Q.front->next, Q.rear);
	ShowTime(Q);
	//getchar();getchar();
	while (!JudgeEmpty(Q)){
		delay(500000);
		time+=timeseg;
		OpProject(Q);
		//getchar();
	}
	return;
}

2.2加一个时间片的各个PCB的分配子函数

状态:0-运行,1-阻塞,2-就绪,3-结束

  1. 赋予各个PCB新的状态,改变BlockTime和StartBlock

    注意:阻塞时间StartBlock只有由1-0=0这一次使得进程进入阻塞状态;同样的,被阻塞时间BlockTime只有由1-0=0这一次使得进程从阻塞状态进入就绪状态

  2. 改变优先级

优先级改变的原则:
2.1进程在就绪队列中呆一个时间片,优先数+1
2.2进程每运行一个时间片,优先数-3

  1. 优先级排序
  2. 如果队头是运行结束的进程,使其出队
    (1)运行结束的进程被设置了奇高的优先级一定在队头;
    (2)每次只运行一个进程,所以一次只会出现一个运行结束的进程
  3. 输出
//一个时间片的时间的各个PCB的分配,状态:0-运行,1-阻塞,2-就绪,3-结束
void OpProject(LinkQueue &Q){
	if (!JudgeEmpty(Q)){
		PCBPtr p = Q.front->next,f=NULL;
		SaveState(Q);//赋予状态
		do{
			if (p->State == 0)//运行的操作
				AddProject(p);
			if (p->State == 2){//就绪优先级+1
				p->priority++;
			}
			
			f = p;
			p = p->next;
		} while (f != Q.rear);
		PrioritySort(Q.front->next, Q.rear);
		PCB t = GetHead(Q);
		if (t.State == 3)
			DeQueue(Q, t);
		ShowTime(Q);//展示
	}
	return;
}
2.2.1赋予各个PCB新的状态

状态:0-运行,1-阻塞,2-就绪,3-结束
因为在这之前输出的进程表总是已按优先级排序过的的
所以这里优先级最高的且不阻塞的就是接下来进入运行状态的进程
遍历整个队列:

  • 运行进程只有一个,找到第一个优先级最高的且不阻塞的赋为运行状态-0
  • 每个每个大于0的StartBlock和BlockTime都随着时间片的消耗而-1;若是由1变为0则触发功能(StartBlock使进程进入阻塞状态-1;BlockTime使阻塞进程进入就绪状态)
  • 若已分配过运行进程后,又遇到状态为0-运行的进程,则赋其为就绪状态-2
//赋予状态:0-运行,1-阻塞,2-就绪,3-结束
void SaveState(LinkQueue &Q){
	PCBPtr p = Q.front->next,f=NULL;
	bool flag = false;
	do{
		if (p->BlockTime > 0&&p->State==1){
			p->BlockTime--;
			if (p->BlockTime == 0)//阻塞变为就绪
				p->State = 2;
		}
		if (p->StartBlock > 0&&(p->State==2||p->State==0)){
			p->StartBlock--;
			if (p->StartBlock == 0)//就绪变为阻塞
				p->State = 1;
		}
		if (!flag && (p->State == 2 || p->State == 0)){//就绪队列中优先级最高的进入运行
			p->State = 0; flag = true;
		}
		else if (flag&&p->State == 0)//有运行的进程后再遇到运行状态就变回就绪状态
			p->State = 2;
		f = p;
		p = p->next;
	} while (f != Q.rear);
	return;
}
2.2.2运行状态的PCB P经历了一个时间片的分配状况
  1. 若未运行完

优先级-3
还需占用时间减少一个时间片
已占用增加一个时间片

  1. 若运行完

优先级赋奇高,这里赋为99,使得快排后其必然在队头
状态赋为结束-3

//运行状态的PCB P经历了一个时间片
void AddProject(PCBPtr &P){
	if (P->AllTime > timeseg){//未运行完
			P->priority -= 3;
			P->AllTime -= timeseg;//还需占用时间减少一个时间片
			P->CPUTime += timeseg;//已占用增加一个时间片
		}
		else{//运行完
			P->priority = 99;
			P->CPUTime += P->AllTime;
			P->AllTime = 0; P->StartBlock = 0; P->BlockTime = 0;
			P->State = 3;
		}
}
  • 5
    点赞
  • 84
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
(1)用C语言来实现对N个进程采用动态优先权优先算法进程调度。 (2)每个用来标识进程的进程控制块PCB用结构来描述,包括以下字段: •••• 进程标识数 ID。 •••• 进程优先数 PRIORITY,并规定优先数越大的进程,其优先权越高。 •••• 进程已占用的CPU时间CPUTIME。 •••• 进程还需占用的CPU时间ALLTIME。当进程运行完毕时,ALLTIME变为0。•••• 进程的阻塞时间STARTBLOCK,表示当进程再运行STARTBLOCK个时间片后,将进入阻塞状态。 •••• 进程被阻塞的时间BLOCKTIME,表示已足赛的进程再等待BLOCKTIME个时间片后,将转换成就绪状态。 •••• 进程状态START。 •••• 队列指针NEXT,用来将PCB排成队列。 (3)优先数改变的原则: •••进程在就绪队列中呆一个时间片,优先数加1。 •••进程每运行一个时间片,优先数减3。 (4)假设在调度前,系统中有5个进程,它们的初始状态如下: ID 0 1 2 3 4 PRIORITY 9 38 30 29 0 CPUTIME 0 0 0 0 0 ALLTIME 3 3 6 3 4 STARTBLOCK 2 -1 -1 -1 -1 BLOCKTIME 3 0 0 0 0 STATE READY READY READY READY READY (5)为了清楚的观察各进程的调度过程,程序应将每个时间片内的情况显示出来,参照的具体格式如下: RUNNING PROG:i READY-QUEUE:->id1->id2 BLOCK-QUEUE:->id3->id4 = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ID 0 1 2 3 4 PRIORITY P0 P1 P2 P3 P4 CUPTIME C0 C1 C2 C3 C4 ALLTIME A0 A1 A2 A3 A4 STARTBLOCK T0 T1 T2 T3 T4 BLOCKTIME B0 B1 B2 B3 B4 STATE S0 S1 S2 S3 S4
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Deosiree

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值