原創
上一篇博客寫了最高優先級算法——進程調度:http://www.cnblogs.com/chiweiming/p/9028002.html
此篇介紹時間片輪轉調度,時間片輪轉調度比最高優先級調度更為簡單,每次都從PCB(進程存在的唯一標識)隊列中將
首進程調入CPU,增加其已用CPU時間,改變其進程狀態;然后判斷其已用CPU時間是否大於等於需要運行時間,大於將
其進程狀態置為完成狀態,否則將此PCB插入隊列尾部,再次在隊列中尋找優先級最高的PCB...兩篇博客的代碼大同小異。
/* 時間片輪轉算法 */ #include<stdio.h> #include<stdlib.h> #include<time.h> #define N 3 #define Time_film 2 //時間片 int count = 0; void print(struct PCB *head); struct PCB{ int process_name; //進程名 int priority_number; //優先數,全置0 int arrive_time; //到達時間,為進程的創建時間 int need_time; //需要運行的時間,隨機產生 int used_time; //已用CPU的時間,初始值為0 int process_state; //進程狀態,1表示運行,0表示完成,-1表示就緒,初始值為-1 struct PCB *cre; //前驅指針域 struct PCB *next; //后驅指針域 }; void Process_scheduling(struct PCB *head){ /* 掃描隊列,將進程按到底順序調入CPU運行; 如果 use_CPU == need_time 撤銷此PCB; 否則用完一個時間片后放回隊列尾部,繼續掃描; */ //**************************** struct PCB *Move=head; struct PCB *Max_Pri=head->next; struct PCB *Tail; //尾指針 //**************************** Move->next = Max_Pri->next; //調出隊列首進程 if(Move->next != NULL){ Move = Max_Pri->next; Move->cre = Max_Pri->cre; } //**************************** printf(" 進程 %d 被調度: \n",Max_Pri->process_name); Max_Pri->used_time += Time_film; //增加CPU占用時間 if(Max_Pri->used_time >= Max_Pri->need_time){ Max_Pri->used_time = Max_Pri->need_time; //進程狀態改變 Max_Pri->process_state = 0; count++; } else{ Max_Pri->process_state = 1; } printf(" %d %d %d %d %d %d \n\n",Max_Pri->process_name,Max_Pri->priority_number,Max_Pri->arrive_time,Max_Pri->need_time,Max_Pri->used_time,Max_Pri->process_state); if(count == N){ //所有進程執行完畢 printf(" 所有進程執行完畢!"); return; } printf(" 就緒隊列:\n"); print(head); //輸出就緒隊列 printf("\n"); //**************************** if(Max_Pri->process_state !=0){ Move = head; while( Move->next!=NULL ){ //當被調出進程未完成時將其插入就緒隊列尾部 Move = Move->next; } Tail = Move; Max_Pri->cre = Tail; Max_Pri->next = NULL; Tail->next = Max_Pri; Max_Pri->process_state = -1; } //**************************** Process_scheduling(head); } void print(struct PCB *head){ //輸出隊列函數 if(head->next == NULL){ printf("就緒隊列已空\n"); return; } printf("name priority arr_time need_time use_CPU pro_state\n"); struct PCB *fry = head->next; while(fry != NULL){ printf(" %d ",fry->process_name); printf("%d ",fry->priority_number); printf("%d ",fry->arrive_time); printf("%d ",fry->need_time); printf("%d ",fry->used_time); printf("%d ",fry->process_state); printf("\n"); fry = fry->next; } printf("\n"); } int main(){ struct PCB *head; //頭指針 struct PCB Pro[N+1]; //創建 N+1 個進程 head = &Pro[0]; srand(time(0)); //**************************** //設置進程參數 Pro[0].process_name = 0; Pro[0].cre = NULL; Pro[0].next = &Pro[1]; Pro[0].priority_number = 0; int i=0; for(i=1;i<=N;i++){ Pro[i].process_name = i; Pro[i].priority_number = 0; Pro[i].arrive_time = i; Pro[i].need_time = rand()%7; while(Pro[i].need_time == 0){ Pro[i].need_time = rand()%7; } Pro[i].used_time = 0; Pro[i].process_state = -1; } for(i=1;i<=N;i++){ //形成雙向隊列 if( i == N ){ Pro[i].cre = &Pro[i-1]; Pro[i].next = NULL; break; } Pro[i].cre = &Pro[i-1]; Pro[i].next = &Pro[i+1]; } //**************************** printf(" 進程初始狀態: \n"); print(head); //輸出初始隊列狀態 Process_scheduling(head); //調用進程調度函數(時間片輪轉) return 0; }
(運行結果部分截圖)
15:52:07
2018-05-13
改進:
上面忽視了進程的到達時間這個因素,會產生這樣的錯誤:
執行了當前進程,但是下一進程未到達,確仍被執行。
創建進程時對進程時間由小到大的賦值;每次從已經到達的進程中順序選擇進程調入CPU運行,可以設置一個動態的系統時間
system_time(初始值為最先到達進程的到達時間)system_time在每個進程執行完一次后都增加該進程此次執行的時間(這里
不指明每次執行時間為時間片是因為當進程剩下需要的執行時間小於一個時間片后system_time不會增加一個時間片),進程每
次執行完一個時間片后,將 system_time與每個進程的到達時間進行比較,大於system_time則未到達,反之,到達;每個進程
執行完一個時間片后判斷是否執行完畢,執行完畢則撤銷,否則將其插入隊列尾部;下次再從隊列首部開始順序查找,隊列掃描
指針指向的進程的到達時間若小於等於system_time則將其調出執行......值得一提的是,若遇到進程到來比較晚即前面的進程都已
經執行完成(已從隊列中移除),則通過system_time將找不到合適的進程調入,此時必須通過 “手動”添加系統時間來達到下一個
進程的到達時間,然后將其執行。
/* 時間片輪轉算法 */ #include<stdio.h> #include<stdlib.h> #include<time.h> #define N 5 #define Time_film 2 //時間片 int count = 0; //統計進程完成個數 int system_time=100; int flag=0; int ff=0; void print(struct PCB *head); struct PCB{ // int fl; int process_name; //進程名 int priority_number; //優先數,隨機產生 int arrive_time; //進程的到達時間,隨機產生 int need_time; //需要運行的時間,隨機產生 int used_time; //已用CPU的時間,初始值為0 int process_state; //進程狀態,1表示運行,0表示完成,-1表示就緒,初始值為-1 struct PCB *cre; //前驅指針域 struct PCB *next; //后驅指針域 }; void Process_scheduling(struct PCB *head){ /* 掃描隊列,將最先到達的進程調入運行,於運行狀態 的進程用完一個時間片后判斷進程是否執行完畢,完畢 則撤銷,否則插入隊列尾部,再從頭掃描隊列,尋找 已經到達的進程。 */ //**************************** struct PCB *Move=head->next; struct PCB *Max_Pri=head; struct PCB *Tail; //尾指針 //**************************** flag=0; ff=0; while(++flag){ Move=head->next; Max_Pri=head; while(Move!=NULL){ //每次從隊列頭部開始掃描,取出已到達進程即可 if(Move->arrive_time<=system_time){ Max_Pri=Move; break; } Move=Move->next; } if(Max_Pri->cre==NULL){ //說明當前沒有到達進程 ff=1; system_time++; //增加系統時間 } else{ break; } } if(ff==1){ printf("暫無進程可執行,等待 %d 后,系統時間為: %d \n\n",flag-1,system_time); } /* Move=hear->next; while(Move!=NULL){ //在幾個同時最早時間到達的進程中選擇優先級最高的 if(Max_Pri->arrive_time == Move->arrive_time){ if(Max_Pri->priority_number>Move->priority_number){ Max_Pri=Move; } } Move=Move->next; } */ /* while(++flag){ Move=head->next; Max_Pri=head; while(Move!=NULL){ if(Move->arrive_time < system_time){ //小於等於系統時間的進程說明已經到達 Max_Pri=Move; } Move=Move->next; } if(Max_Pri->cre==NULL){ //說明沒有選出合適進程,需要增加系統時間 printf("暫無進程可執行,等待 %d 后~\n",flag-2); system_time++; } else{ break; } } */ //**************************** Move = Max_Pri->cre; //將上面選擇的進程調入CPU運行 Move->next = Max_Pri->next; if(Move->next != NULL){ Move = Max_Pri->next; Move->cre = Max_Pri->cre; } //**************************** printf(" 進程 %d 被調度: \n",Max_Pri->process_name); Max_Pri->used_time += Time_film; //增加CPU占用時間 if(Max_Pri->used_time >= Max_Pri->need_time){ if(Max_Pri->used_time==Max_Pri->need_time){ system_time+=Time_film; } if(Max_Pri->used_time > Max_Pri->need_time){ system_time+=(Max_Pri->used_time-Max_Pri->need_time); } Max_Pri->used_time = Max_Pri->need_time; Max_Pri->process_state = 0; //進程狀態改變 count++; } else{ system_time+=Time_film; Max_Pri->process_state = 1; } // Max_Pri->priority_number-=1; //優先數減1 printf(" %d %d %d %d %d %d\n\n",Max_Pri->process_name,Max_Pri->priority_number,Max_Pri->arrive_time,Max_Pri->need_time,Max_Pri->used_time,Max_Pri->process_state); if(count == N){ //所有進程執行完畢 printf(" 所有進程執行完畢!"); return; } if(Max_Pri->process_state==1){ printf("進程 %d 未完成,進入就緒隊列,系統時間為: %d \n\n",Max_Pri->process_name,system_time); } else{ printf("進程 %d 已完成,系統時間為: %d \n\n",Max_Pri->process_name,system_time); } printf(" 就緒隊列:\n"); //**************************** if(Max_Pri->process_state !=0){ Move = head; while( Move->next!=NULL ){ //當被調出進程未完成時將其插入就緒隊列尾部 Move = Move->next; } Tail = Move; Max_Pri->cre = Tail; Max_Pri->next = NULL; Tail->next = Max_Pri; Max_Pri->process_state = -1; } print(head); //**************************** Process_scheduling(head); } void print(struct PCB *head){ //輸出隊列函數 if(head->next == NULL){ printf("就緒隊列已空\n"); return; } printf("name priority arr_time need_time use_CPU pro_state\n"); struct PCB *fry = head->next; while(fry != NULL){ printf(" %d ",fry->process_name); printf("%d ",fry->priority_number); printf("%d ",fry->arrive_time); printf("%d ",fry->need_time); printf("%d ",fry->used_time); printf("%d ",fry->process_state); printf("\n"); fry = fry->next; } printf("\n"); } int main(){ struct PCB *head; //頭指針 struct PCB Pro[N+1]; //創建 N+1 個進程-----就緒狀態隊列 srand(time(0)); //**************************** //設置就緒狀態進程參數 head = &Pro[0]; int i=0; for(i=0;i<=N;i++){ if(i==0){ Pro[i].process_name = 0; Pro[i].cre = NULL; Pro[i].next = &Pro[i+1]; Pro[i].priority_number = -100; Pro[i].arrive_time=-1; // Pro[i].fl=0; continue; } Pro[i].process_name = i; Pro[i].priority_number = rand()%10; while(Pro[i].priority_number == 0){ Pro[i].priority_number = rand()%10; } Pro[i].arrive_time = rand()%(i+i*5); //進程到達時間由小到大的創建 while(Pro[i].arrive_time<Pro[i-1].arrive_time){ Pro[i].arrive_time=rand()%(i+i*5); } Pro[i].need_time = rand()%7; while(Pro[i].need_time == 0){ Pro[i].need_time = rand()%7; } Pro[i].used_time = 0; Pro[i].process_state = -1; // Pro[i].fl=0; } for(i=1;i<=N;i++){ //形成雙向隊列 if( i == N ){ Pro[i].cre = &Pro[i-1]; Pro[i].next = NULL; break; } Pro[i].cre = &Pro[i-1]; Pro[i].next = &Pro[i+1]; /* if(Pro[i].fl==0){ //0代表未被選中 if(Pro[i].arrive_time<min){ min=Pro[i].arrive_time; p=&Pro[i].arrive_time; } } */ /* //**************************** struct PCB *Move; struct PCB *Tail; Move = head; while( Move->next!=NULL ){ //指向尾元素 Move = Move->next; } Tail = Move; p->cre = Tail; //將選出的進程插入就緒隊列 p->next = NULL; Tail->next = p; //**************************** */ } //**************************** for(i=1;i<=N;i++){ //將最先到達進程的時間設置為系統開始時間 if(Pro[i].arrive_time<system_time){ system_time=Pro[i].arrive_time; } } printf("系統時間為: %d \n",system_time); //**************************** printf(" 就緒狀態進程: \n"); print(head); //輸出就緒狀態進程 Process_scheduling(head); //調用進程調度函數(時間片輪轉) return 0; }
(運行結果部分截圖)
17:07:17
2018-05-18