進程調度基本方法及實現


   進程的四大特點: 並發、共享、虛擬、異步。

   進程調度便是實現並發的關鍵一環。

   在操作系統中存在多種調度算法,其中有的調度算法適用於作業調度,有的調度算法適用於進程調度,有的調度算法兩者都適用。

  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;
}

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM