進程的四大特點: 並發、共享、虛擬、異步。
進程調度便是實現並發的關鍵一環。
在操作系統中存在多種調度算法,其中有的調度算法適用於作業調度,有的調度算法適用於進程調度,有的調度算法兩者都適用。
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;
}
