實現操作系統的主要進程調度算法:先來先服務(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");
}