進程的四大特點: 並發、共享、虛擬、異步。
進程調度便是實現並發的關鍵一環。
在操作系統中存在多種調度算法,其中有的調度算法適用於作業調度,有的調度算法適用於進程調度,有的調度算法兩者都適用。
1.先來先服務(FCFS)
一種簡單的調度算法,適用於作業和進程調度。先來先服務算法按照進程/作業到達先后順序來進行調度。當作業調度采用該算法時,每次調度都會從后備隊列中取出最先到達的作業,為他分配內存,創建PCB,放入就緒隊列中;當進程調度采用該算法時,每次調度都會從就緒隊列中取出最先進入該隊列的進程,給他分配處理機(處理機=CPU+主存儲器+IO設備)。
2.短作業優先(SJF)
作業或進程的長短是以作業或進程要求運行時間的長短來衡量的。
3.優先級調度
作業或進程的優先級來確定優先調度權。
(1)靜態優先級 --- 優先級在進程/作業調度前就確定並不會更改。
(2)動態優先級 --- 優先級會隨進程的執行情況而改變,更靈活,科學。
4.時間片輪轉法(RR)
主要用於分時系統的進程調度。進程/作業放在一個隊列上,CPU拿出第一個進程運行一個時間片后,將其放在隊尾,輪詢執行。
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<string.h> #include <algorithm> using namespace std; int choice; //選項 int n; //進程數 bool ok[100] = {0}; //作業完成情況 1為完成 0為未完成 int last[100] = { 0 }; //任務剩余時間 struct pcb{ int pid; //進程號 int atime; //到達時間 int rtime; //運行時間 int stime; //開始時間 int etime; //結束時間 int time; //周轉時間 float dtime; //帶權周轉時間 int priority; //優先級 int timechip; //時間片 }pro[100]; //最大進程數組,輸入輸出參數 //先來先服務算法進程排序規則, 先按照到達時間升序,再按照進程號升序排列 bool fcfscmp(pcb a,pcb b) { if (a.atime != b.atime)return a.atime < b.atime; return a.pid < b.pid; } //動態優先級算法進程排序規則,先按照進程優先數升序,再按到達時間升序,再按進程號升序排列 bool pricmp(pcb a, pcb b) { if (a.priority != b.priority)return a.priority < b.priority; if (a.atime != b.atime)return a.atime < b.atime; return a.pid < b.pid; } //先來先服務 void FCFS() { int t = 0; int dt = 0; //排序到達時間最早的作業 sort(pro + 1, pro + 1 + n, fcfscmp); //依次完成作業 printf("\n==== PID 到達時間 運行時間 開始時間 結束時間 周轉時間 帶權周轉時間 ====\n"); for (int i = 1; i <= n; i++) { pro[i].stime = max(t, pro[i].atime);//開始時間 = max(系統時間,到達時間) pro[i].etime = pro[i].stime + pro[i].rtime; pro[i].time = pro[i].etime - pro[i].atime; //周轉時間 = 結束 - 到達 pro[i].dtime = pro[i].time/pro[i].rtime; //帶權周轉時間 = 周轉時間/運行時間 //總周轉時間,總帶權周轉時間 t += pro[i].time; dt += pro[i].dtime; printf(" %d %d %d %d %d %d %3.3f\n", pro[i].pid, pro[i].atime, pro[i].rtime, pro[i].stime,pro[i].etime,pro[i].time,pro[i].dtime); } float avet = (float)t / n; float avedt = (float)dt / n; printf("平均周轉時間為%3.3f,平均帶權周轉時間為%3.3f\n",avet,avedt); } //短作業優先 void SPF() { //作業完成情況先置0 memset(ok, 0, sizeof(ok)); int t = 0; int dt = 0; int min = 1; printf("\n==== PID 到達時間 運行時間 開始時間 結束時間 周轉時間 帶權周轉時間 ====\n"); for (int i = 1; i <= n; i++) { //1.找出當前最短時間作業 int flag = 0; //標記是否有到達作業 while (flag == 0){ for (int j = 1; j <= n; j++) { if (ok[j] == 1)continue; //已經運行完成的進程 if (pro[j].atime > t)continue; //沒有到達的進程 //出現一個已到達進程 if (pro[j].atime <= t && flag == 0) { min = j; flag = 1; } //出現兩個已到達進程,比較出最短時間進程 else if (pro[j].atime <= t && flag == 1) { if ((pro[j].rtime < pro[min].rtime) || (pro[j].rtime == pro[min].rtime&&pro[j].pid < pro[min].pid)) { //運行時間短的進程優先 運行時間相同時,按順序 min = j; } } }// end of for //此時,沒有進程到達,時間+1 if (flag == 0) t++; } //2.完成作業 pro[i].stime = max(t, pro[min].atime); pro[i].etime = pro[i].stime + pro[min].rtime; pro[i].time = pro[i].etime - pro[i].atime; //周轉時間 = 結束 - 到達 pro[i].dtime = pro[i].time / pro[i].rtime; //帶權周轉時間 = 周轉時間/運行時間 //總周轉時間,總帶權周轉時間 t += pro[i].time; dt += pro[i].dtime; printf(" %d %d %d %d %d %d %3.3f\n", pro[i].pid, pro[i].atime, pro[i].rtime, pro[i].stime, pro[i].etime, pro[i].time, pro[i].dtime); ok[min] = 1; //標記這個進程完成 } float avet = (float)t / n; float avedt = (float)dt / n; printf("平均周轉時間為%3.3f,平均帶權周轉時間為%3.3f\n", avet, avedt); } /*判斷是否全部進程都執行完畢*/ int charge() { for (int i = 1; i<=n; i++) { if (last[i] != 0) return 1; } return 0; } //輪轉法 void RR() { //作業完成數組置0 memset(ok, 0, sizeof(ok)); int t = 0 , dt = 0; sort(pro + 1, pro + n + 1, fcfscmp);//排序:先來先服務原則 --- 有利於后面輪詢 int i = 0; //*關鍵 : 記錄進程剩余時間 for (int i = 1; i <= n; i++) { last[i] = pro[i].rtime; } int chip = pro[1].timechip; //時間片 int time = pro[1].atime; //當前時間的初值 //按順序輪詢,就緒態運行,阻塞態等待到達時間 printf("\n==== PID 到達時間 運行時間 開始時間 結束時間 周轉時間 帶權周轉時間 ====\n"); while (charge()) //能進charge說明還有進程 { int flag = 0; //標記是否還有就緒任務 for (i = 1; i <= n; i++) //時間片輪轉法執行各進程 { if (ok[i] == 1) continue; //已完成的進程 //就緒進程輪轉 if (last[i]<=chip && time>=pro[i].atime)//未完成的進程但是還需服務的時間少於等於一個時間片 { flag = 1; //記錄第一次開始運行時間 if (pro[i].rtime == last[i]) pro[i].stime = time; //開始時間 = 當前時間 //時間更新,任務完成 time += chip; last[i] = 0; ok[i] = 1; pro[i].etime = time; //結束時間 pro[i].time = pro[i].etime - pro[i].atime; //周轉時間 = 結束 - 到達 pro[i].dtime = pro[i].time / pro[i].rtime; //帶權周轉時間 = 周轉時間/運行時間 //總周轉時間,總帶權周轉時間 t += pro[i].time; dt += pro[i].dtime; printf(" %d %d %d %d %d %d %3.3f\n", pro[i].pid, pro[i].atime, pro[i].rtime, pro[i].stime, pro[i].etime, pro[i].time, pro[i].dtime); } else if (last[i]>chip && time>=pro[i].atime)//未完成的進程但其還需服務時間至少大於一個時間片 { flag = 1; //記錄第一次開始運行時間 if (last[i]==pro[i].rtime) pro[i].stime = time; //開始時間 = 當前時間 time += chip; last[i] -= chip; } }//end of for //沒有一個就緒進程,自增時間 if (flag == 0) { time += chip; } }//end of while float avet = (float)t / n; float avedt = (float)dt / n; printf("平均周轉時間為%3.3f,平均帶權周轉時間為%3.3f\n", avet, avedt); } //優先級調度 void PRI() { //作業完成數組置0 memset(ok, 0, sizeof(ok)); int t = 0, dt = 0; sort(pro + 1, pro + n + 1, pricmp);//排序:優先級 int i = 0; //*關鍵 : 記錄進程剩余時間 for (int i = 1; i <= n; i++) { last[i] = pro[i].rtime; } int chip = pro[1].timechip; //時間片 int time = pro[1].atime; //當前時間的初值 //按優先級順序輪詢,輪詢完再次優先級排序 printf("\n==== PID 到達時間 運行時間 開始時間 結束時間 周轉時間 帶權周轉時間 ====\n"); while (charge()) //能進charge說明還有進程 { int flag = 0; //標記是否還有就緒任務 for (i = 1; i <= n; i++) //時間片輪轉法執行各進程 { if (ok[i] == 1) continue; //已完成的進程 //就緒進程輪轉 if (last[i] <= chip && time >= pro[i].atime)//未完成的進程但是還需服務的時間少於等於一個時間片 { flag = 1; //記錄第一次開始運行時間 if (pro[i].rtime == last[i]) pro[i].stime = time; //開始時間 = 當前時間 //時間更新,任務完成 time += chip; last[i] = 0; ok[i] = 1; pro[i].etime = time; //結束時間 pro[i].time = pro[i].etime - pro[i].atime; //周轉時間 = 結束 - 到達 pro[i].dtime = pro[i].time / pro[i].rtime; //帶權周轉時間 = 周轉時間/運行時間 //總周轉時間,總帶權周轉時間 t += pro[i].time; dt += pro[i].dtime; printf(" %d %d %d %d %d %d %3.3f\n", pro[i].pid, pro[i].atime, pro[i].rtime, pro[i].stime, pro[i].etime, pro[i].time, pro[i].dtime); } else if (last[i]>chip && time >= pro[i].atime)//未完成的進程但其還需服務時間至少大於一個時間片 { flag = 1; //記錄第一次開始運行時間 if (last[i] == pro[i].rtime) pro[i].stime = time; //開始時間 = 當前時間 time += chip; last[i] -= chip; pro[i].priority -= 1; //如果沒完成,優先級-1 } }//end of for sort(pro + 1, pro + n + 1, pricmp);//排序:優先級 //沒有一個就緒進程,自增時間 if (flag == 0) { time += chip; } }//end of while float avet = (float)t / n; float avedt = (float)dt / n; printf("平均周轉時間為%3.3f,平均帶權周轉時間為%3.3f\n", avet, avedt); } //輸入界面 void Menu() { while (1){ n = 0; choice = 0; printf("=== 請選擇算法: ===\n* 1.先來先服務 *\n* 2.短作業優先 *\n* 3.時間片輪轉 *\n* 4.優先級調度 *\n* 0.退出 *\n選擇:"); scanf("%d", &choice); if (choice == 0) return; printf("請選擇進程數:"); scanf("%d", &n); printf("*** 請依次寫入 ***\n PID 到達時間 運行時間 優先級 時間片大小:\n"); for (int i = 1; i <= n; ++i) { scanf("%d %d %d %d %d", &pro[i].pid, &pro[i].atime, &pro[i].rtime, &pro[i].priority, &pro[i].timechip); } if (n == 0) return; switch (choice) { case 1:FCFS(); break;//先來先服務調度算法 case 2:SPF(); break;//短作業優先調度算法 case 3:RR(); break;//時間片輪轉調度算法 case 4:PRI(); break;//優先級調度算法 } printf("\n"); } } int main() { Menu(); return 0; }