進程調度--FCFS,SPN,RR算法的實現

實現操作系統的主要進程調度算法:先來先服務(FCFS)算法,短進程優先(SPN)算法和時間片輪轉(RR)算法。


(1)先來先服務調度算法(FCFS)

該算法採用非剝奪策略,算法按照進程提交或進程變爲就緒狀態的先後次序,分派 CPU。當前進程佔用CPU,直到執行完或阻塞,纔出讓CPU(非搶佔方式)。在進程喚醒後(如I/O 完成),並不立即恢復執行,通常等到當前進程出讓CPU。這是最簡單的調度算法,比較有利於長進程,而不利於短進程,有利於CPU 繁忙的進程,而不利於I/O 繁忙的進程。


(2)短進程優先調度算法(SPN)

該算法也採用非剝奪策略,對預計執行時間短的進程優先分派處理機。通常後來的短進程不搶先正在執行的進程。相比FCFS 算法,該算法可改善平均週轉時間和平均帶權週轉時間,縮短進程的等待時間,提高系統的吞吐量。缺點是對長進程非常不利,可能長時間得不到執行,且未能依據進程的緊迫程度來劃分執行的優先級,以及難以準確估計進程的執行時間,從而影響調度性能。


(3)時間片輪轉算法(RR)

該算法採用剝奪策略。讓就緒進程以FCFS 的方式按時間片輪流使用CPU 的調度方式,即將系統中所有的就緒進程按照FCFS 原則,排成一個隊列,每次調度時將CPU 分派給隊首進程,讓其執行一個時間片,時間片的長度從幾個ms 到幾百ms。在一個時間片結束時,發生時鐘中斷,調度程序據此暫停當前進程的執行,將其送到就緒隊列的末尾,並通過上下文切換執行當前的隊首進程,進程可以未使用完一個時間片,就出讓CPU(如阻塞)。時間片輪轉調度算法的特點是簡單易行、平均響應時間短,但不利於處理緊急作業。在時間片輪轉算法中,時間片的大小對系統性能的影響很大,因此時間片的大小應選擇恰當。


使用C語言實現FCFS,SPN,RR算法:

#include<stdio.h>
#include<stdlib.h>

//先來先服務,最短作業優先算法結構體
typedef struct process_FCFS
{
	char name;			//進程名
	float arrivetime;	//到達時間
	float servetime;	//服務時間
	float finishtime;	//完成時間
	float roundtime;	//週轉時間
	float daiquantime;	//帶權週轉時間
	struct process_FCFS *link;//結構體指針

}FCFS; 

//時間片輪轉算法結構體
typedef struct stud
{
	char name;		//進程名
	float arrive;	//進程到達時間
	float run;		//進程運行時間
	float rest;		//運行進程剩餘時間
	char *state;	//進程狀態
	struct stud *next;	//結構體指針
}stud;

FCFS *p,*q,*head=NULL;

struct process_FCFS a[100];
float avrRoundtime;//平均週轉時間
float avrDaiquantime;//平均帶權週轉時間

FCFS initial(struct process_FCFS a[],int n);
void print(struct process_FCFS a[],int n);
void Fcfs(struct process_FCFS a[],int n);	//FCFS算法
void SPN(struct process_FCFS a[],int n);	//SPN算法
struct process_FCFS *sortarrivetime(struct process_FCFS a[],int n);	//到達時間冒泡排序
struct process_FCFS *sortservetime(struct process_FCFS a[],int n);	//服務時間冒泡排序

struct stud *create(int &a);	//初始化創建時間片輪轉算法調度隊列
void RR(struct stud *head, int &a);	//時間片輪轉RR算法

//按到達時間進行冒泡排序
struct process_FCFS *sortarrivetime(struct process_FCFS a[],int n)
{
	int i,j;
	struct process_FCFS t;
	int flag;
	for(i=1;i<n;i++)
	{
		flag=0;
		for(j=0;j<n-i;j++)
		{
			if(a[j].arrivetime>a[j+1].arrivetime)	//將到達時間短的交換到前邊
			{
				t=a[j];
				a[j]=a[j+1];
				a[j+1]=t;
				flag=1;//交換
			}
		}
		if(flag==0)//如果一趟排序中沒發生任何交換,則排序結束	
		{
			break;
		}
	}
	return a;	//返回排序後進程數組
}

//按服務時間進行冒泡排序
struct process_FCFS *sortservetime(struct process_FCFS a[],int n)
{
	int i,j;
	struct process_FCFS t;
	int flag;
	for(i=1;i<n;i++)
	{
		flag=0;
		for(j=1;j<n-i;j++)
		{
			if(a[j].servetime>a[j+1].servetime)	//將到達時間短的交換到前邊
			{
				t=a[j];
				a[j]=a[j+1];
				a[j+1]=t;
				flag=1;//交換
			}
		}
		if(flag==0)//如果一趟排序中沒發生任何交換,則排序結束
		{
			break;
		}
	}
	return a;	//返回排序後進程數組
}


//先來先服務算法
void Fcfs(struct process_FCFS a[],int n,float &t1, float &t2)
{
	int i;
	a[0].finishtime=a[0].arrivetime+a[0].servetime;	//完成時間=到達時間-服務時間
	a[0].roundtime=a[0].finishtime-a[0].arrivetime;	//週轉時間=完成時間-提交時間
	a[0].daiquantime=a[0].roundtime/a[0].servetime;	//帶權時間=週轉時間/服務時間
	for(i=1;i<n;i++)
	{
		if(a[i].arrivetime<a[i-1].finishtime)	//當前到達時間在上一個作業結束時間之前
		{
			a[i].finishtime=a[i-1].finishtime+a[i].servetime;	//完成時間=上一個完成時間+服務時間
			a[i].roundtime=a[i].finishtime-a[i].arrivetime;		//週轉時間=完成時間-到達時間
			a[i].daiquantime=a[i].roundtime/a[i].servetime;		//帶權時間=週轉時間/服務時間
		}
		else	//當前到達時間在上一個作業結束時間之後
		{
			a[i].finishtime=a[i].arrivetime+a[i].servetime;
			a[i].roundtime=a[i].finishtime-a[i].arrivetime;
			a[i].daiquantime=a[i].roundtime/a[i].servetime;
		}

	}
	for(int i=0;i<n;i++)
	{
		printf("進程名:%c",a[i].name);
		printf("到達時間:%f",a[i].arrivetime);
		printf("服務時間:%f",a[i].servetime);
		printf("完成時間:%f",a[i].finishtime);
		printf("週轉時間:%f",a[i].roundtime);
		printf("帶權週轉時間:%f",a[i].daiquantime);
		printf("\n");
		t1 += a[i].roundtime;
		t2 += a[i].daiquantime;
	}
}

//短作業優先算法
void SPN(struct process_FCFS a[],int n,float &t1, float &t2)
{
	int i;

	a[0].finishtime=a[0].arrivetime+a[0].servetime;	//完成時間=到達時間-服務時間
	a[0].roundtime=a[0].finishtime-a[0].arrivetime;	//週轉時間=完成時間-提交時間
	a[0].daiquantime=a[0].roundtime/a[0].servetime;	//帶權時間=週轉時間/服務時間

	for(i=1;i<n;i++)
	{
		if(a[i].arrivetime<a[i-1].finishtime)	//當前到達時間在上一個作業結束時間之前
		{
			a[i].finishtime=a[i-1].finishtime+a[i].servetime;	//完成時間=上一個完成時間+服務時間
			a[i].roundtime=a[i].finishtime-a[i].arrivetime;		//週轉時間=完成時間-到達時間
			a[i].daiquantime=a[i].roundtime/a[i].servetime;		//帶權時間=週轉時間/服務時間
		}
		else	//當前到達時間在上一個作業結束時間之後
		{
			a[i].finishtime=a[i].arrivetime+a[i].servetime;
			a[i].roundtime=a[i].finishtime-a[i].arrivetime;
			a[i].daiquantime=a[i].roundtime/a[i].servetime;
		}

	}
	for(int i=0;i<n;i++)
	{
		printf("進程名:%c",a[i].name);
		printf("到達時間:%f",a[i].arrivetime);
		printf("服務時間:%f",a[i].servetime);
		printf("完成時間:%f",a[i].finishtime);
		printf("週轉時間:%f",a[i].roundtime);
		printf("帶權週轉時間:%f",a[i].daiquantime);
		printf("\n");
		t1 += a[i].roundtime;
		t2 += a[i].daiquantime;
	}
}

//打印輸出函數
void print(struct process_FCFS a[],int n)
{
	int i;

	for(i=0;i<n;i++)
	{
		printf("進程名:%c",a[i].name);
		printf("到達時間:%f",a[i].arrivetime);
		printf("服務時間:%f",a[i].servetime);
		printf("完成時間:%f",a[i].finishtime);
		printf("週轉時間:%f",a[i].roundtime);
		printf("帶權週轉時間:%f",a[i].daiquantime);
		printf("\n");
	}

}

//初始化創建調度隊列
struct stud *create(int &a)
{
	int i;
	struct stud *head, *rear,*p,*q,*t;
	head=rear=NULL;

	for(i=0;i<a;i++)
	{
		p=(struct stud*)malloc(sizeof(struct stud));

		printf("%d 進程名: ",i+1);
		scanf("%s",&p->name);
		printf("到達時間:");
		scanf("%f",&p->arrive);
		printf("服務時間:");
		scanf("%f",&p->run);

		p->rest = p->run;
		p->state = "ready";		 	 	     	    
		if(rear == NULL)
		{
			head = p;
			p->next = NULL;
			rear = p;
		}
		else
		{
			t = NULL;
			q = head;
			while(q && q->arrive < p->arrive)
			{
				t = q;
				q = q->next;
			}

			if(q == head)
			{
				p->next = head;
				head = p;
			}
			else if(t == rear)
			{
				rear->next = p;
				p->next = NULL;
				rear = p;
			}
			else
			{
				t->next = p;
				p->next = q;
			}
		}

	}
	return head;

}

//時間片輪轉算法
void RR(struct stud *head, int &a)
{
	struct stud *p,*t,*r;
	float slice = 0.0f;
	float temp = 0.0f;	//緩存最後一個正數rest
	float m1 = 0.0f , m2 = 0.0f, n1 = 0.0f, n2 = 0.0f;
	float sum_zhouzhuan = 0.0f, sum_daiquan = 0.0f;	//所有進程總週轉時間,所有進程總帶權週轉時間
	float zhouzhuan = 0.0f, daiquan = 0.0f;	//週轉時間,帶權週轉時間
	float avr_zhouzhuan = 0.0f, avr_daiquan = 0.0f;
	printf("請輸入時間塊大小: ");
	scanf("%f",&slice);
	while(head != NULL)	//隊列非空,循環
	{
		r = p = head;
		while(p != NULL)	//遍歷隊列,結束後跳出當前循環
		{
			t = head;	
			m1 += slice;
			temp = p->rest;
			p->rest = p->rest - slice;	//剩餘時間                    

			p->state = "running";	
			if(p->rest <= 0)
			{
				m1 = m1 - slice + temp;		//進程完成時間
				zhouzhuan = m1 - p->arrive;		//進程週轉時間
				daiquan = zhouzhuan / (p->run);	//進程帶權週轉時間
				sum_zhouzhuan += zhouzhuan;				//所有進程週轉時間之和
				sum_daiquan += daiquan;
				p->rest = 0;
			}
			printf("\n-----------------------------------------------\n");
			printf("name\tarrive\trun\trest\tstate\n");
			while(t != NULL)
			{
				printf("%d\t%f\t%f\t%f\t%s\n",t->name,t->arrive,t->run,t->rest,t->state);
				t = t->next;
			}
			if(p->rest == 0)/*判斷是否刪除結點*/
			{ 

				//finishtime += 
				if(p == head)/*刪除頭結點*/
				{
					head = p->next;
					free(p);
					p = head;
				}
				else
				{
					r->next = p->next;
					p = r->next;
					r = p;
				}
			}
			else 
			{
				r = p;
				p->state = "ready";	 	 
				p = p->next;
			}
		}   	
	}
	printf("\n總週轉時間: ");
	printf("%f", sum_zhouzhuan);
	printf("\n總帶權週轉時間: ");
	printf("%f\n", sum_daiquan);

	avr_zhouzhuan = sum_zhouzhuan / a;
	avr_daiquan = sum_daiquan / a;

	printf("\n平均週轉時間: ");
	printf("%f",avr_zhouzhuan);
	printf("\n平均帶權週轉時間: ");
	printf("%f\n",avr_daiquan);
}


//主函數
void main()
{
	float t1 = 0.0f;	//總週轉時間
	float t2 = 0.0f;	//總帶權週轉時間
	float avr_t1 = 0.0f;	//平均週轉時間
	float avr_t2 = 0.0f;	//平均帶權週轉時間

	int n,i;
	char select = ' ';	//選擇算法變量標識
	while (select != 'e' && select != 'E')	//不爲退出標識,保持循環
	{
		printf("請選擇算法:\na.先來先服務算法\nb.短作業優先算法\nc.時間片輪轉算法\ne.退出程序\n輸入選擇字符標號:  ");
		scanf("%c",&select);
		if (select == 'a' || select == 'A')	//先來先服務算法
		{
			printf("\n\n=================先來先服務算法================\n\n");
			printf("請輸入進程數:");
			scanf("%d",&n);
			for(i=0;i<n;i++)
			{
				printf("%d 進程名: ",i+1);
				scanf("%s",&a[i].name);
				printf("到達時間:");
				scanf("%f",&a[i].arrivetime);
				printf("服務時間:");
				scanf("%f",&a[i].servetime);
			}

			sortarrivetime(a, n);	//冒泡排序
			Fcfs(a,n,t1,t2);	//先來先服務算法
			avr_t1 = t1 / n;
			avr_t2 = t2 / n;
			printf("\n");
			printf("平均週轉時間爲:%f \n", avr_t1);
			printf("平均帶權週轉時間爲:%f \n", avr_t2);
		}

		else if (select == 'b' || select == 'B')	//短作業優先算法
		{
			printf("\n\n=================短作業優先算法================\n\n");

			printf("請輸入進程數:");
			scanf("%d",&n);
			for(i=0;i<n;i++)
			{
				printf("%d 進程名: ",i+1);
				scanf("%s",&a[i].name);
				printf("到達時間:");
				scanf("%f",&a[i].arrivetime);
				printf("服務時間:");
				scanf("%f",&a[i].servetime);
			}
			sortservetime(a, n);	//冒泡排序
			SPN(a,n,t1,t2);	//短作業優先算法
			avr_t1 = t1 / n;
			avr_t2 = t2 / n;
			printf("\n");
			printf("平均週轉時間爲:%f \n", avr_t1);
			printf("平均帶權週轉時間爲:%f \n", avr_t2);
			
		}

		else if (select == 'c' || select == 'C')	//時間片輪轉算法
		{
			printf("\n\n=================時間片輪轉算法================\n\n");
			int a;
			printf("請輸入進程數: ");
			scanf("%d",&a);
			struct stud *head;
			head = create(a);
			RR(head, a) ;  
		}

	}
	system("pause");
}


發佈了67 篇原創文章 · 獲贊 18 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章