文章目錄
題目
代碼
#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", ×eg);
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菜單
- 輸入,依次進隊
- 先快排一次,並輸出(時刻0)
- 進入無限循環直到隊空結束
3.1.延時
3.2.加一個時間片的時間
3.3進入加一個時間片的各個PCB的分配子函數(裏頭兼有快排及輸出)
//菜單
//菜單
void menu(LinkQueue &Q){
printf("請輸入進程數:");
scanf("%d", &n);
printf("請設置時間片長度:");
scanf("%d", ×eg);
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-結束
-
賦予各個PCB新的狀態,改變BlockTime和StartBlock
注意:阻塞時間StartBlock只有由1-0=0這一次使得進程進入阻塞狀態;同樣的,被阻塞時間BlockTime只有由1-0=0這一次使得進程從阻塞狀態進入就緒狀態
-
改變優先級
優先級改變的原則:
2.1進程在就緒隊列中呆一個時間片,優先數+1
2.2進程每運行一個時間片,優先數-3
- 優先級排序
- 如果隊頭是運行結束的進程,使其出隊
(1)運行結束的進程被設置了奇高的優先級一定在隊頭;
(2)每次只運行一個進程,所以一次只會出現一個運行結束的進程 - 輸出
//一個時間片的時間的各個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經歷了一個時間片的分配狀況
- 若未運行完
優先級-3
還需佔用時間減少一個時間片
已佔用增加一個時間片
- 若運行完
優先級賦奇高,這裏賦爲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;
}
}