动态优先权进程调度算法

题目

在这里插入图片描述

代码

#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;
		}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章