動態優先權進程調度算法

題目

在這裏插入圖片描述

代碼

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