LInux實驗 : 程式排程模擬

陳杉菜發表於2020-12-24

實驗概述

在作業系統中用c語言實現對N個程式採用動態優先權的程式排程,輸入例項為:
假設在排程前,系統有5個程式,具有如下狀態

5
9 0 3 2 3
38 0 3 1 1
30 0 6 4 2
29 0 3 1 1
0 0 4 1 2
1

每個標示程式的程式控制看PCB用結構體來描述,包括程式id,程式優先順序priority,越大優先順序別越高,已佔用CPU時間cputime,還需佔用CPU時間alltime,程式阻塞時間starblock,程式被阻塞時間blocktime,基礎狀態state

預設輸出程式排程式列的id,以空格分隔,當輸入的最後一行為1時,輸出每一步的系統狀態。

優先數改變的原則:程式在就緒佇列中呆一個時間片,優先數增加1,程式每執行一個時間片優先數減3。

實驗內容

結構PCB

首先使用結構PCB來描述程式,

struct PCB  
{  
	 int ID;//程式id  
	 int PRIORITY;//程式優先順序,越大越優先  
	 int CPUTIME;//已經執行的時間片  
	 int ALLTIME;//還要執行的時間片  
	 int STARTBLOCK;//程式開始變成BLCOK的時間片  
	 int BLOCKTIME;//經過BLCOKTIME之後程式由BLOCK轉變成READY  
	 int STATE;//程式的狀態READY--1,BLOCK--2  
	 PCB *next;//指向下一個程式  
};

除卻上述講到的程式id,程式優先順序priority,越大優先順序別越高,已佔用CPU時間cputime,還需佔用CPU時間alltime,程式阻塞時間starblock,程式被阻塞時間blocktime,基礎狀態state等屬性之外,還需增加一個指向下一個程式的指標。

動態優先數是指在程式建立時先確定一個初始優先數, 以後在程式執行中隨著程式特性的改變不斷修改優先數,這樣,由於開始優先數很低而得不到CPU的程式,就能因為等待時間的增長而優先數變為最高而得到CPU執行。

因此,為了排程方便,初始化就緒佇列,阻塞佇列和CPU之後,先把給定的程式從大到小連成佇列,包含頭節點,用指標給出佇列的連線情況。若佇列不為空,就緒佇列首程式就開始投入執行,時間片執行完成,程式已佔有的CPU時間+1,當執行程式已佔用的時間達到所需要的執行時間時進行判斷,若程式完成則促銷改程式,若還未完成就將該執行程式的優先數-1.並把該執行程式插入到就緒佇列中去。再根據優先數改變的原則,程式在就緒佇列中呆一個時間片,優先數增加1,程式每執行一個時間片優先數減3,排程程式狀態並顯示。

重要函式程式碼

1.排程演算法

	void MyDispatcher()  
	{  
	    if(!Is_CPU_Busy)//CPU空閒  
	    {  
	        Running_p=GetFirstProcess(Ready_Queue_Head);//獲取就緒佇列優先順序最高的程式  
	          
	    }  
	    else//CPU不空閒  
	    {  
	        if(!Is_Empty_Queue(Ready_Queue_Head) &&  Ready_Queue_Head->next->PRIORITY>Running_p->PRIORITY)//如果就緒佇列的程式中存在優先順序比running process的優先順序大就應該搶佔CPU  
	        {  
	            InsetProcess(Running_p,Ready_Queue_Head);//把執行中的程式進隊  
	            Running_p=GetFirstProcess(Ready_Queue_Head);//把running_p設為最新的優先順序最大的程式  
	        }  
	    }  
	} 

2.CPU函式

	void CPUWork()  
	{  
	    Is_CPU_Busy=true;  
	    //執行Running_p......  
	    Cur_Time++;  
	    Running_p->ALLTIME--;  
	    Running_p->CPUTIME++;  
	    Running_p->PRIORITY-=3;  
	   
	    Update_Ready_Queue();  
	    Update_Block_Queue();  
	    if(Running_p->BLOCKTIME>0 && Running_p->STARTBLOCK==Running_p->CPUTIME)//如果程式阻塞了  
	    {  
	        Running_p->STATE=BLOCK;  
	        InsetProcess(Running_p,Block_Queue_Head);  
	        Is_CPU_Busy=false;  
	        MyDispatcher();  
	        Is_CPU_Busy=true;  
	    }  
	    if(Running_p->ALLTIME==0)//如果程式順利完結  
	    {  
	        Is_CPU_Busy=false;  
	        MyDispatcher();  
	        Is_CPU_Busy=true;  
	    }     
	} 

3.佇列更新函式:

	void Update_Block_Queue()  
	{  
	    PCB *p=Block_Queue_Head->next;  
	    PCB *p_before=Block_Queue_Head;  
	    while(p!=NULL)  
	    {  
	        //p->PRIORITY++;  
	        p->BLOCKTIME--;  
	        if(p->BLOCKTIME==0)//變回就緒狀態  
	        {  
	            p_before->next=p->next;//把該程式從阻塞佇列中刪去  
	            p->STATE=READY;  
	            InsetProcess(p,Ready_Queue_Head);//把改程式插回就緒佇列  
	            p=p_before->next;  
	        }  
	        else  
	        {  
	            p_before=p;  
	            p=p->next;  
	        }  
	    }  

主要程式碼分析

輸入PCB資訊,即保證CPU,就緒佇列和阻塞佇列中的程式數不為0。
1.先判斷CPU是否空閒。CPU空閒的話,從就緒佇列中選取優先順序最大的;而如果就緒佇列為空,則從阻塞佇列中選取第一個程式。選中的程式的cputime設定為0。CPU上有程式的話,就更新CPU上程式的狀態,列印CPU上程式的id。如果CPU上的程式的alltime已經為0,即程式已經完成了,更新該程式的狀態為finish,將CPU清空。如果程式在CPU上的時間達到starttime,將其放到阻塞佇列,清空CPU。
2.更新阻塞佇列和就緒佇列中的程式中的狀態,列印就緒佇列和阻塞佇列的程式的id。
3.列印每個程式的狀態。
迴圈操作直至CPU,就緒佇列和阻塞佇列中都沒有程式為止。

程式碼最終執行結果截圖(前2個時間片和第18個時間片):

1

相關文章