原創
最近幾周操作系統實習,要求完成幾道題目,下面是自己敲出來的模擬在單處理器情況下的進程調度算法(說算法可能過於高大尚),
采用的是短作業優先調度算法、時間片輪轉調度、最高優先級優先算法三種算法中的最高優先級算法。
題目闡述如下:
設計一:進程調度
設計目的:
進程管理是操作系統中的重要功能,用來創建進程、撤消進程、實現進程狀態轉換,它提供了在可運行的進程之間復用CPU的方法。
在進程管理中,進程調度是核心,因為在采用多道程序設計的系統中,往往有若干個進程同時處於就緒狀態,當就緒進程個數大於處
理器數目時,就必須依照某種策略決定哪些進程優先占用處理器。本設計模擬在單處理器情況下的進程調度,目的是加深對進程調度
工作的理解,掌握不同調度算法的優缺點。
設計內容:
設計程序模擬單處理機系統中的進程調度算法,在短作業優先調度算法、時間片輪轉調度、最高優先級優先算法三種算法中選擇兩種實現。
每個進程由一個進程控制塊(PCB)表示。進程控制塊可以包含如下信息:進程名、優先數、到達時間、需要運行時間、已用CPU時間、進
程狀態等。進程的優先數及需要的運行時間可以事先人為地指定(也可以由隨機數產生)。進程的到達時間為進程輸入的時間。
進程的運行時間以時間片為單位進行計算。
每個進程的狀態可以是就緒W(Wait)、運行R(Run)或完成F(Finish)3中狀態之一。
以下是最高優先級優先算法思想:
就緒進程獲得CPU后都只能運行一個時間片,用已占用CPU時間加1來表示。
如果運行一個時間片后,進程的已占用CPU時間已達到所需要的運行時間,則撤銷該進程,如果運行一個時間片后進程的已占用CPU時間
還未達到所需要的運行時間,也即進程還需要繼續運行,此時應將進程的優先數減1(即降低一級),然后把它插入就緒隊列等待CPU。
每進行一次調度程序都打印一次運行進程、就緒隊列以及各個進程的PCB,以便進行檢查。
重復以上過程,直到所有進程都完成為止。
每個PCB進程包括:進程名、優先數、到達時間、需要運行時間、已用CPU時間、進程狀態;采用結構體類型來存儲一個PCB。
采用的數據結構是隊列,創建的進程形成一個雙向隊列(采用雙向隊列容易尋找前驅結點的地址),遍歷隊列,從中找出優先級
最高的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; //優先數,隨機產生 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){ /* 掃描隊列,尋找最高優先數的PCB,調入CPU運行; 如果 use_CPU == need_time 撤銷此PCB; 否則用完一個時間片后放回隊列尾部,繼續掃描; */ //**************************** struct PCB *Move=head->next; struct PCB *Max_Pri=head->next; struct PCB *Tail; //尾指針 //**************************** while(Move!=NULL){ if(Max_Pri->priority_number < Move->priority_number){ Max_Pri = Move; } //尋找最高優先級進程 Move = Move->next; } //**************************** Move = Max_Pri->cre; //將最高優先級進程調出 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; } 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; } 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 = rand()%10; while(Pro[i].priority_number == 0){ Pro[i].priority_number = rand()%10; } 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; }
(運行結果部分截圖)
10:58:00
2018-05-12
改進:
上面忽視了進程的到達時間這個因素,會產生致命錯誤:
進程沒有到達,但是其優先級最高,還是會被調用!
必須從已經到達的進程中選擇優先級最高的調入CPU運行,每個進程每次使用一次時間片后必須判斷哪些進程已經到來,然后再
從所有到達的進程中選擇優先級最高的調入CPU運行;可以設置一個動態的系統時間 system_time(初始值為最先到達進程的到
達時間)system_time 在每個進程執行完一次后都增加該進程此次執行的時間(這里不指明每次執行時間為時間片是因為當進程
剩下需要的執行時間小於一個時間片后 system_time 不會增加一個時間片),進程每次執行完一個時間片后,將 system_time
與每個進程的到達時間進行比較,大於 system_time 則未到達,反之,到達;再從已到達的進程中選擇優先級最高的調入CPU運
行......值得一提的是,若遇到進程到來比較晚( 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 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; //尾指針 //**************************** /* while(Move!=NULL){ if(Max_Pri->arrive_time > Move->arrive_time){ //尋找最早到達的進程 Max_Pri = Move; } Move = Move->next; } 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; } */ flag=0; ff=0; while(++flag){ Move=head->next; Max_Pri=head; while(Move!=NULL){ if(Move->arrive_time <= system_time){ //小於等於系統時間的進程說明已經到達,小於系統時間的進程都要相互比較優先級 if(Move->priority_number>Max_Pri->priority_number){ Max_Pri=Move; } } 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 = 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; 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()%10; 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]; } //**************************** 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; }
(運行結果部分截圖)
16:31:29
2018-05-18
