作業系統原理之處理器排程實驗
實驗原理與內容
三、實驗原理
假定系統有五個程序,每一個程序用一個程序控制塊PCB來代表。程序控制塊的格式為:
程序名 |
時間 |
要求求執行時間 |
優先數 |
狀態 |
其中,程序名----作為程序的標識,假設五個程序的程序名分別是P1,P2,P3,P4,P5。
指標----按優先數的大小把五個程序連成佇列,用指標指出下一個程序的程序控制塊
首地址,最後一個程序中的指標為“0”。
要求執行時間----假設程序需要執行的單位時間數。
優先數----賦予程序的優先數,排程時總是選取優先數大的程序先執行。
狀態----可假設有兩種狀態,“就緒”狀態和“結束“狀態,五個程序的初始狀態都為“就緒“狀態,用“R”表示,當一個程序執行結束後,它的狀態變為“結束”,
用“E”表示。
在每次執行你所設計的處理器排程程式之前,為每個程序任意確定它的“優先數”和“要求執行時間”。
為了排程方便,把五個程序按給定的優先數從大到小連成佇列,用一單元指出隊首程序,用指標指出佇列的連線情況。例:
隊首標誌
k2 |
k1 k2 k3 k4 k5
P1 |
0 |
2 |
1 |
P3 |
k5 |
1 |
3 |
P5 |
k1 |
4 |
2 |
P4 |
k3 |
2 |
4 |
P2 |
k4 |
3 |
5 |
R |
R |
R |
R |
R |
PCB1 PCB2 PCB3 PCB4 PCB5
處理器排程總是選隊首程序執行。採用動態改變優先數的辦法,程序每執行一次優先數就減“1”。由於本實驗是模擬處理器排程,所以,對被選中的程序並不實際的啟動執行,而是執行:
優先數-1
要求執行時間-1
來模擬程序的一次執行。
提醒注意的是:在實際的系統中,當一個程序被選中執行時,必須恢復程序的現場,它佔有處理器執行,直到出現等待事件或執行結束。在這裡省去了這些工作。
程序執行一次後,若要求執行時間≠0,則再將它加入佇列(按優先數大小插入,且置隊首標誌);若要求執行時間=0,則把它的狀態修改為“結束”(),且退出佇列。
若“就緒”狀態的程序佇列不為空,則重複上面(4)和(5)的步驟,直到所有程序都成為“結束”狀態。
在所設計的稱序中應有顯示或列印語句,能顯示或列印每次被選中程序的程序名以及執行一次後進稱對列的變化。
為五個程序任意確定一組“優先數”和“要求執行時間”,啟動所設計的處理器排程程式,顯示或列印逐次被選中程序的程序名以及程序控制塊的動態變化過程。
實驗過程與結果(可貼圖)
一.實驗題目
設計一個按優先數排程演算法實現處理器排程的程序。
//定義結構體,包含五個屬性,名字,下一個PCB指標,執行時間,優先順序,目前狀態
(一) 程式中使用的資料結構及符號說明。
本程式採用的程序結構體為PCB
struct PCB /*程序控制塊結構體,包含識別符號、優先數、執行時間、狀態、前後指標*/
{
charname[6]; /*程序識別符號*/
intrun_time; /*程序執行時間*/
intprior_num; /*程序優先數*/
charstatus; /*程序狀態:R-就緒,E-結束*/
structPCB *pre; /*指向後一程序的指標*/
structPCB *next; /*指向後一程序的指標*/
};
/*資料結構為雙鏈表*/
struct PCB *head; /*程序連結串列的頭指標*/
struct PCB *tail; /*程序連結串列的尾指標*/
(四)源程式
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int num = 5; /*假定程序數為5*/
struct PCB*head; /*程序連結串列的頭指標*/
struct PCB*tail; /*程序連結串列的尾指標*/
intglobal_time; /*定義全域性時間*/
struct PCB*PCBinit(struct PCB *q); /*初始化程序連結串列*/
struct PCB*init(struct PCB *p, int i); /*初始化程序*/
void sort(structPCB *phead); /*氣泡排序連結串列*/
voidexchange(struct PCB *p, struct PCB *max); /*交換相鄰兩個程序的指標*/
void run(structPCB *p); /*模擬執行程序*/
voidshowinfor(struct PCB *head); /*輸出程序資訊*/
voidcheck_runtime(struct PCB *p);/*判斷執行時間是否為0*/
struct PCB /*程序控制塊結構體,包含識別符號、優先數、執行時間、狀態、前後指標*/
{
char name[6]; /*程序識別符號*/
int run_time; /*程序執行時間*/
int prior_num; /*程序優先數*/
char status; /*程序狀態:R-就緒,E-結束*/
struct PCB *pre; /*指向後一程序的指標*/
struct PCB *next; /*指向後一程序的指標*/
};
//初始化程序
struct PCB*init(struct PCB *p, int i){
//初始化程序名
p->name[0] = 'P';
p->name[1] = 'C';
p->name[2] = 'B';
p->name[3] = i+1+'0';
//為程序指定執行時間
printf("程序 %s\n",p->name);
printf("請確定該程序的執行時間:");
scanf("%d", &p->run_time);
//為程序指定優先數
printf("請確定該程序的優先數:");
scanf("%d",&p->prior_num);
printf("\n");
//初始化程序狀態為就緒
p->status = 'R';
//初始化指向後一程序的指標為空
p->next = NULL;
//返回程序
return p;
}
//初始化程序連結串列
struct PCB*PCBinit(struct PCB *q){
int i;
struct PCB *p = NULL; /*p為待執行佇列PCB指標*/
head = tail = NULL; /*初始化頭尾指標*/
for(i = 0; i < num; i++){
p = (struct PCB*)malloc(sizeof(struct PCB)); //分配空間,讓p指向這個PCB
init(p,i); //初始化程序
p->next = NULL;
if(head == NULL){ //連線程序
tail = head = p;
p->pre = NULL;
}else{
p->pre = tail;
tail->next = p;
tail = p;
}
}
return p;
}
//氣泡排序連結串列
void sort(structPCB *phead){
struct PCB *a, *b; //定義程序a,b
int i;
for(i=0;i<num;i++){ //外迴圈迴圈次數取決於全域性變數num,相當於連結串列長度
a = head; //初始化程序a為head
b = head->next; //初始化程序b為head->next
while(b != NULL){ //b非空
if(a->prior_num <b->prior_num){ //比較程序a,b的優先數
exchange(a,b); //呼叫exchange函式交換a,b程序指標
a = a->pre; //實現一次指標交換要重置a,b程序位置
b = b->next; //因為指標交換資料不變
}
a = a->next; //完成一次內迴圈後
b = b->next; //指標順延
}
}
}
//交換相鄰兩個程序的指標
void exchange(structPCB *p, struct PCB *max){
if(p == max | max != p->next){ //判斷若兩個程序不相鄰,則返回
return;
}
if(max == p->next){ //程序相鄰
if(p->pre != NULL){ //程序p指向前一程序的指標不為空
p->pre->next = max; //將p的前一程序的後指標指向max
}else{ //程序p的前一程序指標為空。則說明p原是head指向的程序
head = max; //將頭指標指向max
}
if(max->next != NULL){ //max的下一程序指標不為空
max->next->pre=p; //將max的下一程序的前指標指向p
}
max->pre = p->pre; //將max的前一指標指向p的前一指標
p->next = max->next; //將p的後一指標指向max的後一指標
max->next = p; //max的後一指標指向p
p->pre = max; //p的前一指標指向max
}//本方法用於實現氣泡排序中程序結構體只轉換指標,不轉換資料
}
//輸出程序資訊
voidshowinfor(struct PCB *phead){
struct PCB *p;
for(p = phead; p != NULL; p =p->next){
printf("程序 %s\t 優先數 %d\t 執行時間 %d\t 狀態 %c\n",p->name,p->prior_num,p->run_time,p->status);
}
}
//執行函式
void run(structPCB *p){
//輸出這個任務的狀態,全域性時間加1,任務還需要的時間減1,優先順序減1
global_time++; //全域性時間加1
p->run_time--; //執行時間減1
if(p->prior_num > 0) // 優先數需大於0
p->prior_num--; //優先數減1
printf("第 %d 次執行:\n",global_time);
printf("當前程序: %s\t 優先數 %d\t 執行時間:%d\n", p->name, p->prior_num, p->run_time);
printf("\n");
}
//判斷執行時間是否為0
voidcheck_runtime(struct PCB *p){
if(p->run_time <= 0){ //當執行時間為0,結束程序
p->status = 'E'; //修改程序狀態
printf("程序 %s 已結束",p->name);
printf("\n");
printf("程序當前狀態為:\n");
showinfor(head); //顯示程序資訊
printf("\n");
printf("-----------------------------------------------------\n");
printf("請按回車鍵進行下一程序");
printf("\n");
getchar(); //接收回車鍵
free(p); //釋放p記憶體
head = p->next; //將頭指標順延
}
}
void main(){
struct PCB *p = NULL; /*p為待執行佇列PCB指標*/
//初始化程序連結串列
PCBinit(p);
//按優先數遞減進行程序連結串列排序
sort(head);
printf("程序當前狀態為:\n");
showinfor(head); //顯示程序資訊
printf("\n");
//若連結串列中還有PCB是執行迴圈語句
while(head != NULL){
p = head; //p指向第一個程序
run(p); //進行排程
check_runtime(p); //判斷執行時間是否為0
}
}
(五)程式執行時的初值和執行結果