1. 程式人生 > >作業系統程序排程實現演算法(c語言版)

作業系統程序排程實現演算法(c語言版)

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>   //包含sleep函式


#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFESIBLE -1
#define OVERFLOW -2


struct PCB
{
char name[20];       //程序名
int Arrive_Time;     //到達時間
int Serve_Time;      //服務時間
//int Finish_Time;     //完成時間
int priority;        //優先順序
};




typedef struct LNode            //連結串列結點定義
{
PCB data;
struct LNode *next;
}LNode,*LinkList;


typedef struct Queue            //反饋佇列結點定義,實質上還是一個單鏈表
{
PCB data;                 
int prio;                  //反饋佇列的優先順序
int timeblock;             //反饋佇列分配的時間片
struct Queue *next;        //指向下一個反饋佇列的指標
}Queue,*LinkQueue;


int Create(LinkList &L)           //利用尾插法建立程序
{
LinkList p,r;
int i,n;
L=(LinkList)malloc(sizeof(LNode));
L->next=NULL;
r=L;
printf("請輸入程序的個數:\n");
scanf("%d",&n);
if(n<=0)
{
printf("請輸入正整數!\n");
return ERROR;
}
printf("請依次輸入程序名、到達時間、服務時間、優先順序\n");
for(i=0;i<n;i++)
{
p=(LinkList)malloc(sizeof(LNode));
scanf("%s",&(p->data.name));
scanf("%d",&(p->data.Arrive_Time));
scanf("%d",&(p->data.Serve_Time));
//scanf("%d",&(p->data.Finish_Time));
scanf("%d",&(p->data.priority));
r->next=p;
r=p;
}
r->next=NULL;
return OK;
}


int Show(LinkList L)           //輸出當前佇列中的程序的資訊
{
LinkList p;
p=L->next;
if(!p)
{
printf("為空!\n");
return ERROR;
}
while(p)
{
printf("程序名:%s  到達時間:%d  服務時間:%d  優先順序:%d\n",p->data.name,p->data.Arrive_Time,p->data.Serve_Time,p->data.priority);
p=p->next;
}
return OK;
}


void Sort(LinkList &L)   //按照到達時間先後排序
{
LinkList p,q;
PCB temp;
p=L->next;
q=L->next;
while((p!=NULL)&&(p->next!=NULL))       //當建立的佇列中有兩個及以上佇列的時候,利用氣泡排序法按照到達時間先後進行排序
{
for(p=L->next;p->next!=NULL;p=p->next)
{
for(q=L->next;q->next!=NULL;q=q->next)
{
if(q->data.Arrive_Time>q->next->data.Arrive_Time)
{
temp=q->data;
q->data=q->next->data;
q->next->data=temp;
}
}
}
}
}


int getCount(LinkList &L,int time)      //檢視當前就緒佇列中的程序數,其中time是巨集觀執行時間
{
int count=0;
LinkList q;
q=L->next;
while(q!=NULL&&q->data.Arrive_Time<=time)
{
count++;
q=q->next;
}
return count;
}


void Delet(LinkList &L,LinkList p)   //刪除結點函式,刪除p的下一個結點
{
LinkList q;
q=p->next;
p->next=q->next;
free(q);
}


/*----------------------------------------------------------先來先服務演算法-----------------------------------------------------------*/
void FCFS(LinkList &L)
{
LinkList p,q;
int time=0,count;
while(L->next!=NULL)
{
p=L->next;
count=getCount(L,time);
if(count=0)
time++;
else
{
printf("\n");
q=L;
printf("程序%s正在執行……\n",p->data.name);
printf("程序%s開始執行的時間為:%d\n",p->data.name,time);
time+=p->data.Serve_Time;
printf("程序%s完成的時間為:%d\n",p->data.name,time);
printf("程序%s的週轉時間為:%d\n",p->data.name,time-p->data.Arrive_Time);
Delet(L,q);
printf("\n");
}
}
}


/*---------------------------------------------------------短作業優先排程演算法----------------------------------------------------------*/
/*演算法思想:注意變數time的使用,非常關鍵,它能夠將就緒佇列中有哪些程序動態的表示出來,同時能從開始排程程序為止,時間的變化(以1為單位)*/
/*輸入樣例:P1 1 2 0;  P2 0 1 2;  P3 0 3 1;                                                                                                */




LinkList Min(LinkList &L,int count)           //求當前就緒佇列中服務時間最短的程序,並返回該程序結點的上一結點
{
LinkList p,q,flag;
int flagnum=0;       //用來標記flag變數值是否改變
int min;
p=L->next;
q=L->next;
flag=L->next;
min=p->data.Serve_Time;
while(count>0)
{
if(p->data.Serve_Time<min)
{
min=p->data.Serve_Time;
flag=q;                           //注意變數q儲存的是p所指向的上一節點的資訊,一定要引入q,否則會出現排程程序為空的現象
flagnum=1;
}
count--;
q=p;
p=p->next;
}
if(flagnum==0)
flag=L;
return flag;                              //標記最小服務時間的結點的前一個結點的指標
}


void SJP(LinkList &L)        //短作業優先排程演算法的主體模組
{
int time=0,count;
LinkList p,q;
while(L->next!=NULL)
{
count=getCount(L,time);
if(count==0)       //如果當前佇列中沒有程序,那麼就讓時間加一
time++;
else if(count==1)  //如果就緒佇列中只有1個程序
{
//printf("this is one!\n");
p=L->next;
printf("程序%s正在執行……\n",p->data.name);
Sleep(2000);
printf("開始執行的時間:%d\n",time);
time+=p->data.Serve_Time;
printf("程序%s完成時間:%d\n",p->data.name,time);
q=L;
Delet(L,q);
printf("\n");
}
else   //如果就緒佇列中有兩個以上的程序,先排程執行服務時間短的程序
{
//printf("this is two!\n");           此句為除錯資訊,可以不用要
q=Min(L,count);
//printf("q所指程序為:%s\n",q->data.name);    此句為除錯資訊,主要是指明指標q所指的結點,避免出現亂碼的現象
p=q->next;
printf("程序%s正在執行……\n",p->data.name);
Sleep(2000);
printf("開始執行的時間:%d\n",time);
time+=p->data.Serve_Time;
printf("程序%s完成時間:%d\n",p->data.name,time);
Delet(L,q);
printf("\n");
}
//Show(L);             由於是在L中進行操作,所以本句是為了監控L中結點的變化,便於除錯
}
}


/*----------------------------------------------------------非搶佔式的優先順序排程演算法-------------------------------------------------------*/
/*演算法思想:和短作業優先排程演算法一致,只不過短作業優先排程演算法的優先順序是服務時間,而非搶佔式的優先順序排程演算法的優先順序則是人為設定的         */
/* 輸入樣例:p1 1 2 0; p2 0 1 2; p3 0 3 1;                                                                                                 */


LinkList Max_Priority(LinkList &L,int count)            //求就緒佇列中優先順序最高的程序結點(預設數字小的優先順序高)
{
LinkList p,q,flag;
int flagnum=0;
p=L->next;
flag=p;
q=L->next;
int max;
max=p->data.priority;
while(count>0)
{
if(p->data.priority<max)
{
max=p->data.priority;
flag=q;
flagnum=1;
}
count--;
q=p;
p=p->next;
}
if(flagnum==0)
flag=L;
return flag;
}


void Non_priority(LinkList &L)       //非搶佔式優先順序排程演算法
{
int time=0,count;
LinkList p,q;
while(L->next!=NULL)
{
count=getCount(L,time);
//printf("count的值為:%d\n",count);  此句為除錯語句,通過輸出count的值來監控執行的是下面if……else if語句中的哪個模組
if(count==0)
time++;
else if(count==1)
{
p=L->next;
printf("程序%s正在排程……\n",p->data.name);
Sleep(2000);
printf("程序%s開始排程的時間為:%d\n",p->data.name,time);
time+=p->data.Serve_Time;
printf("程序%s完成時間為:%d\n",p->data.name,time);
q=L;
Delet(L,q);
printf("\n");
}
else
{
p=Max_Priority(L,count);
q=p->next;
printf("程序%s正在排程……\n",q->data.name);
Sleep(2000);
printf("程序%s開始排程的時間為:%d\n",q->data.name,time);
time+=q->data.Serve_Time;
printf("程序%s完成時間為:%d\n",q->data.name,time);
Delet(L,p);
printf("\n");
}
//Show(L);  除錯語句
}
}


/*------------------------------------------------------搶佔式優先順序排程演算法---------------------------------------------------------------*/
/*演算法思想:在非搶佔式優先順序排程演算法上進行改進,每執行1s,就判斷一次當前就緒佇列中是否有比當前正在執行的程序優先順序高的,如果有則讓優先順序高的
程序先執行*/
/*測試用例:P1 1 3 0    P2 0 2 2    P3  0 2 1
*/


void Pre_priority(LinkList &L)
{
int time=0,count;
LinkList p,q;
while(L->next!=NULL)
{
count=getCount(L,time);               //判斷當前時間內,就緒佇列裡有多少程序
if(count==0)
time++;                           //如果沒有,則將時間加一,再進行判斷
if(count==1)
{
q=L;
p=q->next;
printf("程序%s執行1s\n",p->data.name);
time++;
p->data.Serve_Time--;
if(p->data.Serve_Time==0)
{
printf("程序%s的完成時間為:%d\n",p->data.name,time);
printf("程序%s的週轉時間為:%d\n",p->data.name,time-p->data.Arrive_Time);
Delet(L,q);                 //【重點】這裡的引數一定要填q,而不是p,因為定義的函式Delet刪除的是p所指向結點的下一個結點
}
printf("\n");
}
if(count>=2)
{
q=Max_Priority(L,count);
p=q->next;
printf("程序%s執行1s\n",p->data.name);
time++;
p->data.Serve_Time--;
if(p->data.Serve_Time==0)
{
printf("程序%s的完成時間為:%d\n",p->data.name,time);
printf("程序%s的週轉時間為:%d\n",p->data.name,time-p->data.Arrive_Time);
Delet(L,q);            //同上
}
//Show(L);  除錯語句
printf("\n");
}
}
}


/*---------------------------------------------------多級反饋佇列排程演算法-----------------------------------------------------------------*/
/*演算法思想:設定三個反饋佇列L1,L2,L3,同一佇列中採用先來先服務演算法,只有當優先順序高的佇列中沒有可以排程的佇列,排程下一級反饋佇列,最後
一級佇列中採用時間片輪轉演算法,取連結串列L中的第一個結點插入到Q1,注意time_的引用*/
/*測試用例:p1 0 6 0            Q1: 1 2
            P2 1 4 0            Q2: 2 2
P3 2 2 0            Q3: 3 4
*/


void Create_Q(LinkQueue &Q)
{
Q=(LinkQueue)malloc(sizeof(Queue));
Q->next=NULL;
}


void Create_DuojiQ(LinkQueue &Q1,LinkQueue &Q2,LinkQueue &Q3)
{
Create_Q(Q1);
Create_Q(Q2);
Create_Q(Q3);
printf("請依次輸入三級反饋佇列的優先順序和時間片!\n");
printf("Q1:\t");
scanf("%d%d",&Q1->prio,&Q1->timeblock);
printf("Q2:\t");
scanf("%d%d",&Q2->prio,&Q2->timeblock);
printf("Q3:\t");
scanf("%d%d",&Q3->prio,&Q3->timeblock);
}


void Delet_(LinkQueue &Q,LinkQueue p)   //刪除結點函式,刪除p的下一個結點
{
LinkQueue q;
q=p->next;
p->next=q->next;
free(q);
}


void Output(LinkQueue Q)
{
LinkQueue q;
q=Q->next;
while(q!=NULL)
{
printf("程序名:%s  到達時間:%d  服務時間:%d\n",q->data.name,q->data.Arrive_Time,q->data.Serve_Time);
q=q->next;
}
}




void InsertEnd1(LinkList &L,LinkQueue &Q)   //取L的隊頭元素插入到Q佇列的末尾
{
LinkList p,q;
LinkQueue m,n,r;
p=L;
q=L->next;
m=Q->next;
r=Q;


if(m==NULL&&(q!=NULL))
{
n=(LinkQueue)malloc(sizeof(Queue));
n->data=q->data;
Delet(L,p);
r->next=n;
r=n;
}
else if(m!=NULL&&(q!=NULL))
{
q=L->next;
while(m->next!=NULL)              //注意這裡一定要是m->next!=NULL,不能寫成且能夠m!=NULL
m=m->next;
r=m;
n=(LinkQueue)malloc(sizeof(Queue));
n->data=q->data;
Delet(L,p);
r->next=n;
r=n;
}
r->next=NULL;


}


void InsertEnd2(LinkQueue &Q1,LinkQueue &Q2)   //取Q1的隊頭元素插入到Q2佇列的末尾,
{
LinkQueue p,q;
LinkQueue m,n,r;
p=Q1;
q=Q1->next;
m=Q2->next;
r=Q2;
if(m==NULL&&(q!=NULL))
{
n=(LinkQueue)malloc(sizeof(Queue));
n->data=q->data;
Delet_(Q1,p);
r->next=n;
r=n;
}
else if(m!=NULL&&(q!=NULL))            //Q2不為空的時候

while(m->next!=NULL)              //注意這裡一定要是m->next!=NULL,不能寫成且能夠m!=NULL
m=m->next;
r=m;
n=(LinkQueue)malloc(sizeof(Queue));
n->data=q->data;
r->next=n;
r=n;
Delet_(Q1,p);
}
r->next=NULL;


}


int getCount_(LinkQueue &Q,int time_)      //檢視當前就緒佇列中的程序數,其中time是巨集觀執行時間
{
int count_=0;
LinkQueue q;
q=Q->next;
while(q!=NULL&&q->data.Arrive_Time<=time_)
{
count_++;
q=q->next;
}
return count_;
}






void Run(LinkQueue &Q1,LinkQueue &Q2,int &time_)            //根據每個佇列分配的時間片,按照先來先服務演算法執行
{
LinkQueue p,q;
int count_;
while(Q1->next!=NULL)
{
p=Q1->next;
count_=getCount_(Q1,time_);
if(count_=0)
time_++;
else
{
q=Q1;
if(p->data.Serve_Time<=Q1->timeblock)
{
printf("程序%s正在執行……\n",p->data.name);
printf("程序%s開始執行的時間為:%d\n",p->data.name,time_);
time_+=p->data.Serve_Time;
printf("程序%s完成的時間為:%d\n",p->data.name,time_);
printf("程序%s的週轉時間為:%d\n",p->data.name,time_-p->data.Arrive_Time);
Delet_(Q1,q);          //這裡的刪除函式不能省
printf("\n");
}
else
{
printf("程序%s正在執行……\n",p->data.name);
printf("程序%s開始執行的時間為:%d\n",p->data.name,time_);
time_+=Q1->timeblock;
p->data.Serve_Time-=Q1->timeblock;
printf("程序%s消耗%d個時間片,轉入下一級反饋佇列\n",p->data.name,Q1->timeblock);
InsertEnd2(Q1,Q2);
//Delet_(Q1,q);     //因為InsertEnd2中包含了刪除,所以此處不能多此一舉
}
}
}
}


void TimeRound(LinkQueue &Q3,int &time_)              //時間片輪轉演算法
{
LinkQueue q,p;
q=Q3->next;                              
while(Q3->next!=NULL)
{
p=Q3;
q=Q3->next;               //【重點】雖然在上面已經對q進行初始化,但是由於下面的else語句中的InsertEnd2中
                          //裡面巢狀呼叫了Delet_函式,頭結點發生了變化,故在while迴圈裡還需要再初始化一次
printf("程序%s執行1s\n",q->data.name);
time_++;
q->data.Serve_Time--;
printf("Serve_Time 的值為:%d\n",q->data.Serve_Time);
if(q->data.Serve_Time==0)
{
printf("程序%s已經完成,完成時間為:%d\n",q->data.name,time_);
Delet_(Q3,p);
}
else
{
InsertEnd2(Q3,Q3);
//Delet_(Q3,p);           注意InsertEnd2中已經刪掉了插入的結點,所以這裡不需要多次一句
}
}
}


void MultiDispatch(LinkList &L,LinkQueue &Q1,LinkQueue &Q2,LinkQueue &Q3)      //多級反饋佇列排程演算法
{
int time_=0,count_;
LinkList p;
p=L;
Create_DuojiQ(Q1,Q2,Q3);
while(L->next!=NULL)
{
InsertEnd1(L,Q1);
//Output(Q1);            除錯語句
//Delet(L,p);           //此處不需要,因為在InsertEnd1函式中已經把插入的結點從L中刪除過了
}
while(Q1->next!=NULL)
{
printf("\n");
printf("^-^當前反饋佇列為Q1 ^-^\n");
Run(Q1,Q2,time_);
}
while(Q2->next!=NULL)
{
printf("\n");
printf("^-^當前反饋佇列為Q2 ^-^\n");
Run(Q2,Q3,time_);
}
while(Q3->next!=NULL)
{
printf("\n");
printf("^-^當前反饋佇列為Q3 ^-^\n");
TimeRound(Q3,time_);
}
}


/*-----------------------------------------------------------主函式-----------------------------------------------------------------------*/


void main()
{
LinkList L;
LinkQueue Q1,Q2,Q3;
int x;
printf("-------------------程序排程------------------\n");
printf("                1.   建立程序                \n");
printf("                2. 顯示程序資訊              \n");
printf("                3.先來先服務演算法             \n");
printf("                4.短作業優先演算法             \n");
printf("                5.非搶佔式優先順序排程演算法     \n");
printf("                6.搶佔式優先順序排程演算法       \n");
printf("                7.多級反饋佇列演算法           \n");
printf("                8.退出                       \n");
printf("---------------------------------------------\n");
while(1)
{
printf("Choice:\t");
scanf("%d",&x);
switch(x)
{
case 1:
Create(L);
Sort(L);
break;
case 2:
Show(L);
break;
case 3:
FCFS(L);
break;
case 4:
SJP(L);
break;
case 5:
Non_priority(L);
break;
case 6:
Pre_priority(L);
break;
case 7:
MultiDispatch(L,Q1,Q2,Q3);
break;
case 8:
exit(0);
}
}
}