實 驗 報 告(拓展實驗1)
多級反饋隊列調度算法
課程名稱 操作系統實驗
學生學院 計算機學院
專業班級 17網絡工程一班
學 號 31170050**
學生姓名 陳鴻
指導教師 林穗
2019 年 12 月 6 日
目錄
void InsertFinish(PCB *in); /*將進程插入到完成隊列尾部*/ 5
void InsertPrio(ReadyQueue *in); /*創建就緒隊列,規定優先數越小,優先級越低*/ 5
void PrioCreate(); /*創建就緒隊列輸入函數*/ 5
void GetFirst(ReadyQueue *queue); /*取得某一個就緒隊列中的隊頭進程*/ 5
void InsertLast(PCB *in,ReadyQueue *queue); /*將進程插入到就緒隊列尾部*/ 5
void ProcessCreate(); /*進程創建函數*/ 5
void RoundRun(ReadyQueue *timechip); /*時間片輪轉調度算法*/ 5
void MultiDispatch(); /*多級調度算法,每次執行一個時間片*/ 5
Tips:建議打開word【導航視圖】與【批注】閱讀。
拓展實驗1:多級反饋隊列調度算法
-
實驗目的
分析操作系統的核心功能模塊,理解相關功能模塊實現的數據結構和算法,並加以實現,加深對操作系統原理和實現過程的理解。本次實驗: 分析並實現多級反饋隊列調度算法的模擬。
二、實驗內容
多級反饋隊列調度算法的概念:
是一種根據先來先服務原則給就緒隊列排序,為就緒隊列賦予不同的優先級數,不同的時間片,按照優先級搶占CPU的調度算法。算法的實施過程如下:
(1)按照先來先服務原則排序,設置N個就緒隊列為Q1,Q2...QN,每個隊列中都可以放很多作業;
(2)為這N個就緒隊列賦予不同的優先級,第一個隊列的優先級最高,第二個隊列次之,其余各隊列的優先權逐個降低;
(3)設置每個就緒隊列的時間片,優先權越高,算法賦予隊列的時間片越小。時間片大小的設定按照實際作業(進程)的需要調整;
(4)進程在進入待調度的隊列等待時,首先進入優先級最高的Q1等待。
(5)首先調度優先級高的隊列中的進程。若高優先級中隊列中已沒有調度的進程,則調度次優先級隊列中的進程。例如:Q1,Q2,Q3三個隊列,只有在Q1中沒有進程等待時才去調度Q2,同理,只有Q1,Q2都為空時才會去調度Q3。
(6)對於同一個隊列中的各個進程,按照時間片輪轉法調度。比如Q1隊列的時間片為N,那么Q1中的作業在經歷了時間片為N的時間后,若還沒有完成,則進入Q2隊列等待,若Q2的時間片用完后作業還不能完成,一直進入下一級隊列,直至完成。
(7)在低優先級的隊列中的進程在運行時,又有新到達的作業,那么在運行完這個時間片后,CPU馬上分配給新到達的作業即搶占式調度CPU。
應用范圍:
此算法應用於同一個資源的多個使用者可分優先級使用資源的情況。
三、實現思路
1、設置多個就緒隊列,並給隊列賦予不同的優先級數,第一個最高,依次遞減。
2、賦予各個隊列中進程執行時間片的大小,優先級越高的隊列,時間片越小。
3、當一個新進程進入內存后,首先將其放入一個對列末尾,如果在一個時間片
結束時尚未完成,將其轉入第二隊列末尾。
4、當一個進程從一個對列移至第n個隊列后,便在第n個隊列中采用時間片輪轉執行完。
5、僅當時間片空閑時,才調度第二個隊列中的進程。
(1~i-1)空閑時,才調度i,如果處理機正在第i隊列中運行,又有新進程進入優先權較高
隊列,則新進程搶占處理機,將正在運行的進程放入第i隊列隊尾,將處理機分給新進程。
四、主要的數據結構
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node /*進程節點信息*/
{
char name[20]; /*進程的名字*/
int prio; /*進程的優先級*/
int round; /*分配CPU的時間片*/
int cputime; /*CPU執行時間*/
int needtime; /*進程執行所需要的時間*/
char state; /*進程的狀態,W--就緒態,R--執行態,F--完成態*/
int count; /*記錄執行的次數*/
struct node *next; /*鏈表指針*/
}PCB;
typedef struct Queue /*多級就緒隊列節點信息*/
{
PCB *LinkPCB; /*就緒隊列中的進程隊列指針*/
int prio; /*本就緒隊列的優先級*/
int round; /*本就緒隊列所分配的時間片*/
struct Queue *next; /*指向下一個就緒隊列的鏈表指針*/
}ReadyQueue;
PCB *run=NULL,*finish=NULL; /*定義三個隊列,就緒隊列,執行隊列和完成隊列*/
ReadyQueue *Head = NULL; /*定義第一個就緒隊列*/
int num; /*進程個數*/
int ReadyNum; /*就緒隊列個數*/
void Output(); /*進程信息輸出函數*/
void InsertFinish(PCB *in); /*將進程插入到完成隊列尾部*/
void InsertPrio(ReadyQueue *in); /*創建就緒隊列,規定優先數越小,優先級越低*/
void PrioCreate(); /*創建就緒隊列輸入函數*/
void GetFirst(ReadyQueue *queue); /*取得某一個就緒隊列中的隊頭進程*/
void InsertLast(PCB *in,ReadyQueue *queue); /*將進程插入到就緒隊列尾部*/
void ProcessCreate(); /*進程創建函數*/
void RoundRun(ReadyQueue *timechip); /*時間片輪轉調度算法*/
void MultiDispatch(); /*多級調度算法,每次執行一個時間片*/
int main(void)
{
PrioCreate(); /*創建就緒隊列*/
ProcessCreate();/*創建就緒進程隊列*/
MultiDispatch();/*算法開始*/
Output(); /*輸出最終的調度序列*/
return 0;
}
void Output() /*進程信息輸出函數*/
{
ReadyQueue *print = Head;
PCB *p;
printf("進程名\t優先級\t輪數\tcpu時間\t需要時間\t進程狀態\t計數器\n");
while(print)
{
if(print ->LinkPCB != NULL)
{
p=print ->LinkPCB;
while(p)
{
printf("%s\t%d\t%d\t%d\t%d\t\t%c\t\t%d\n",p->name,p->prio,p->round,p->cputime,p->needtime,p->state,p->count);
p = p->next;
}
}
print = print->next;
}
p = finish;
while(p!=NULL)
{
printf("%s\t%d\t%d\t%d\t%d\t\t%c\t\t%d\n",p->name,p->prio,p->round,p->cputime,p->needtime,p->state,p->count);
p = p->next;
}
p = run;
while(p!=NULL)
{
printf("%s\t%d\t%d\t%d\t%d\t\t%c\t\t%d\n",p->name,p->prio,p->round,p->cputime,p->needtime,p->state,p->count);
p = p->next;
}
}
void InsertFinish(PCB *in) /*將進程插入到完成隊列尾部*/ {
PCB *fst;
fst = finish;
if(finish == NULL)
{
in->next = finish;
finish = in;
}
else
{
while(fst->next != NULL)
{
fst = fst->next;
}
in ->next = fst ->next;
fst ->next = in;
}
}
void InsertPrio(ReadyQueue *in) /*創建就緒隊列,規定優先數越小,優先級越低*/
{
ReadyQueue *fst,*nxt;
fst = nxt = Head;
if(Head == NULL) /*如果沒有隊列,則為第一個元素*/
{
in->next = Head;
Head = in;
}
else /*查到合適的位置進行插入*/
{
if(in ->prio >= fst ->prio) /*比第一個還要大,則插入到隊頭*/
{
in->next = Head;
Head = in;
}
else
{
while(fst->next != NULL) /*移動指針查找第一個別它小的元素的位置進行插入*/
{
nxt = fst;
fst = fst->next;
}
if(fst ->next == NULL) /*已經搜索到隊尾,則其優先級數最小,將其插入到隊尾即可*/
{
in ->next = fst ->next;
fst ->next = in;
}
else /*插入到隊列中*/
{
nxt = in;
in ->next = fst;
}
}
}
}
void PrioCreate() /*創建就緒隊列輸入函數*/
{
ReadyQueue *tmp;
int i;
printf("輸入就緒隊列的個數:\n");
scanf("%d",&ReadyNum);
printf("輸入每個就緒隊列的CPU時間片:\n");
for(i = 0;i < ReadyNum; i++)
{
if((tmp = (ReadyQueue *)malloc(sizeof(ReadyQueue)))==NULL)
{
perror("malloc");
exit(1);
}
scanf("%d",&(tmp->round)); /*輸入此就緒隊列中給每個進程所分配的CPU時間片*/
tmp ->prio = 50 - tmp->round; /*設置其優先級,時間片越高,其優先級越低*/
tmp ->LinkPCB = NULL; /*初始化其連接的進程隊列為空*/
tmp ->next = NULL;
InsertPrio(tmp); /*按照優先級從高到低,建立多個就緒隊列*/
}
}
void GetFirst(ReadyQueue *queue) /*取得某一個就緒隊列中的隊頭進程*/
{
run = queue ->LinkPCB;
if(queue ->LinkPCB != NULL)
{
run ->state = 'R';
queue ->LinkPCB = queue ->LinkPCB ->next;
run ->next = NULL;
}
}
void InsertLast(PCB *in,ReadyQueue *queue) /*將進程插入到就緒隊列尾部*/
{
PCB *fst;
fst = queue->LinkPCB;
if( queue->LinkPCB == NULL)
{
in->next = queue->LinkPCB;
queue->LinkPCB = in;
}
else
{
while(fst->next != NULL)
{
fst = fst->next;
}
in ->next = fst ->next;
fst ->next = in;
}
}
void ProcessCreate() /*進程創建函數*/
{
PCB *tmp;
int i;
printf("輸入進程的個數:\n");
scanf("%d",&num);
printf("輸入進程名字和進程所需時間:\n");
for(i = 0;i < num; i++)
{
if((tmp = (PCB *)malloc(sizeof(PCB)))==NULL)
{
perror("malloc");
exit(1);
}
scanf("%s",tmp->name);
getchar(); /*吸收回車符號*/
scanf("%d",&(tmp->needtime));
tmp ->cputime = 0;
tmp ->state ='W';
tmp ->prio = 50 - tmp->needtime; /*設置其優先級,需要的時間越多,優先級越低*/
tmp ->round = Head ->round;
tmp ->count = 0;
InsertLast(tmp,Head); /*按照優先級從高到低,插入到就緒隊列*/
}
}
void RoundRun(ReadyQueue *timechip) /*時間片輪轉調度算法*/
{
int flag = 1;
GetFirst(timechip);
while(run != NULL)
{
while(flag)
{
run->count++;
run->cputime++;
run->needtime--;
if(run->needtime == 0) /*進程執行完畢*/
{
run ->state = 'F';
InsertFinish(run);
flag = 0;
}
else if(run->count == timechip ->round)/*時間片用完*/
{
run->state = 'W';
run->count = 0; /*計數器清零,為下次做准備*/
InsertLast(run,timechip);
flag = 0;
}
}
flag = 1;
GetFirst(timechip);
}
}
void MultiDispatch() /*多級調度算法,每次執行一個時間片*/
{
int flag = 1;
int k = 0;
ReadyQueue *point;
point = Head;
GetFirst(point);
while(run != NULL)
{
Output();
if(Head ->LinkPCB!=NULL)
point = Head;
while(flag) {
run->count++;
run->cputime++;
run->needtime--;
if(run->needtime == 0) /*進程執行完畢*/
{
run ->state = 'F';
InsertFinish(run);
flag = 0;
}
else if(run->count == run->round)/*時間片用完*/
{
run->state = 'W';
run->count = 0; /*計數器清零,為下次做准備*/
if(point ->next!=NULL)
{
run ->round = point->next ->round;/*設置其時間片是下一個就緒隊列的時間片*/
InsertLast(run,point->next); /*將進程插入到下一個就緒隊列中*/
flag = 0;
}
else {
RoundRun(point); /*如果為最后一個就緒隊列就調用時間片輪轉算法*/
break;
}
}
++k;
if(k == 3) {
ProcessCreate();
}
}
flag = 1;
if(point ->LinkPCB == NULL)/*就緒隊列指針下移*/
point =point->next;
if(point ->next ==NULL)
{
RoundRun(point);
break;
}
GetFirst(point);
}
}
五、算法流程圖
六、運行與測試
用例描述:
假設系統中有3個就緒隊列Q1,Q2,Q3,時間片分別為2,4,8。
現在有3個作業J1,J2,J3它們所需要的CPU時間分別是3,2,1個時間片。
1、時刻0: J1到達。於是進入到隊列1 , 運行1個時間片 , 時間片還未到,此時J2到達。
2、時刻1: J2到達。 由於時間片仍然由J1掌控,於是等待。 J1在運行了1個時間片后,已經完成了在Q1中的2個時間片的限制,於是J1置於Q2等待被調度。現在處理機分配給J2。
3、時刻2: J1進入Q2等待調度,J2獲得CPU開始運行。
4、時刻3:J3到達,由於J2的時間片未到,故J3在Q1等待調度,J1也在Q2等待調度。
5、時刻4:J2處理完成,由於J3,J1都在等待調度,但是J3所在的隊列比J1所在的隊列的優先級要高,於是J3被調度,J1繼續在Q2等待。
6、時刻5:J3經過1個時間片,完成。
7、時刻6:由於Q1已經空閑,於是開始調度Q2中的作業,則J1得到處理器開始運行。
8、時刻7:J1再經過一個時間片,完成了任務。於是整個調度過程結束。
運行截圖:
七、總結
多級反饋隊列調度算法體現了計算思維的調度特點,應用了先來先服務原則、應用時間片等做法使得每個申請者都能及時使用資源,是一種很好的協調整體的解決方案。