計算機操作系統實驗之進程調度(二)優先級調度法(C語言)
實驗目的
1、理解進程調度的任務、機制和方式
2、瞭解優先級調度算法的基本原理
實驗內容與基本要求
用C,C++等語言編寫程序,模擬使用靜態優先級調度算法實現進程調度
優先級調度算法的基本內容
在時間片輪轉調度算法中,有一個隱含的假設:系統中所有進程的緊迫性是一致的。但是在實際中並不是如此,因此實際在進程調度算法中引入“優先級”這個概念,形成了優先級調度算法。
優先級調度算法,就是把處理機分配給就緒隊列中優先級最高的進程。現在的問題是:處理機正在執行目前就緒隊列中優先級最高的進程B,此時又出現了另一個優先級更高的進程A,系統該如何處理?針對這個問題的不同處理方式,形成了優先級調度算法的兩個類型:一種是搶佔式的優先級調度算法,一種是非搶佔式的優先級調度算法。
- 搶佔式優先級調度算法:在這種算法中,只要出現了一個優先級更高的進程A,就停止正在執行的進程B,讓A立刻投入執行
- 非搶佔式優先級調度算法:在這種算法中,處理機已經分配給了進程B,就讓B一直執行結束,或等B自動放棄處理機時,纔將處理機分配給A
優先級調度算法的核心問題是:如何確定進程的優先級?
優先級根據性質的不同,也分爲兩種類型:靜態優先級和動態優先級。
- 靜態優先級:在進程創建時就決定,並且在進程的整個運行期間保持不變
- 動態優先級:在進程創建時先賦予一個優先級,但是其值會隨着進程的推進或等待時間的增加而改變。
靜態優先級容易實現,但是可能會出現優先級低的進程始終無法被調度的情況。而動態優先級根據不同的規定來計算優先級,有利於促進進程調度的公平性。
實現思路
用輪轉調度法類似,進程PCB的結構和進程隊列的設置方式不變,只是調度的方法有區別而已。
附:上篇輪轉調度法 計算機操作系統實驗之進程調度(一)輪轉調度法(C語言)
PCB的屬性包括:1.進程名字2.進程優先級3.進程的狀態4.時間片5.總共需要的運行時間6.cpu時間(已運行時間)7.還需要運行的時間8.計數器9.下一個要執行的進程指針。
仍然使用帶頭結點的單鏈表來存儲進程隊列,已完成的進程不移出隊列,而是沉到隊列底部。
本次實驗實現的是非搶佔式的靜態優先級調度方式,優先級在進程創建時就決定好(可以由隨機數生成,也可以讓用戶自己輸入)。由於是非搶佔式的,因此每個進程只會獲得一次處理機,無論它的執行時間是多長,都要執行完後纔會調度下一個進程。
至於具體怎麼實現調度,有兩種思路:第一種是在每次調度時去查找隊列中未完成的優先級最大的進程,將它的狀態變爲完成。第二種是:先將隊列按優先級順序排序,然後再依次執行。本次實驗採用的是第二種,因此額外寫了方法,用於按優先級排序。排序的方法是:將鏈表從頭結點處斷開,依次取出首元結點後的每個結點,對鏈表進行按值(優先級的值)插入,優先級從大到小排列。
算法流程圖
全部代碼
工程圖
ProcessScheduling.h
//
// ProcessScheduling.h
// ProcessSchedulingTest
//
// Created by Apple on 2019/10/21.
// Copyright © 2019 Yao YongXin. All rights reserved.
//
#ifndef ProcessScheduling_h
#define ProcessScheduling_h
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <time.h>
#define TIME_SLICE 2
//線程狀態:就緒 等待 完成
enum process_type{
process_type_waitting = 'W',
process_type_ready = 'R',
process_type_finish = 'F'
};
//進程控制塊結構體
typedef struct PCB_Type{
//進程的名字
char *name;
//進程的優先級
int priority;
//仍需運行時間
int need_time;
//進程的狀態 就緒 等待
char state;
//時間片
int time_slice;
//cpu時間 ->已運行時間
int cpu_time;
//計數器
int time_count;
//總共需要的運行時間
int total_time;
//下一個要執行的進程
struct PCB_Type *next;
}PCB;
//創建新的進程
void create_process(PCB *running_list,char *name,int need_time);
void create_process1(PCB *running_list,char *name,int need_time,int priority);
//展示當前就緒隊列狀態
void show(PCB *running_list);
//優先級調度法
void priority_scheduling(PCB *running_list);
//按優先級大小對隊列進行排序
void sort(PCB *running_list);
//找到當前未執行的優先級最高的進程,將它狀態變爲就緒
void set_ready(PCB *running_list);
#endif /* ProcessScheduling_h */
ProcessScheduling.c
//
// ProcessScheduling.c
// ProcessSchedulingTest
//
// Created by Apple on 2019/10/21.
// Copyright © 2019 Yao YongXin. All rights reserved.
//
#include "ProcessScheduling.h"
//創建新的進程->優先級隨機數生成
void create_process(PCB *running_list,char *name,int need_time){
//申請一個內存控制塊的空間
PCB *p = (PCB *)malloc(sizeof(PCB));
assert(p != NULL);
//設置該控制塊的值
p->name = name;
p->need_time = need_time;
//狀態
p->state = process_type_waitting;
//時間片
p->time_slice = 0;
//cpu時間
p->cpu_time = 0;
//計數器
p->time_count = 0;
//總需用時
p->total_time = need_time;
//優先級->隨機數生成
srand((unsigned)time(NULL));
int priority = rand() % 50 + 1;
p->priority = priority;
//下個進程
p->next = NULL;
//放入運行隊列中
PCB *s = running_list;
while (s->next != NULL) {
s = s->next;
}
s->next = p;
}
void create_process1(PCB *running_list,char *name,int need_time,int priority){
//申請一個內存控制塊的空間
PCB *p = (PCB *)malloc(sizeof(PCB));
assert(p != NULL);
//設置該控制塊的值
p->name = name;
p->need_time = need_time;
//狀態
p->state = process_type_waitting;
//時間片
p->time_slice = 0;
//cpu時間
p->cpu_time = 0;
//計數器
p->time_count = 0;
//總需用時
p->total_time = need_time;
//優先級
p->priority = priority;
//下個進程
p->next = NULL;
//放入運行隊列中
PCB *s = running_list;
while (s->next != NULL) {
s = s->next;
}
s->next = p;
}
//展示當前就緒隊列狀態
void show(PCB *running_list){
PCB *p = running_list->next;
if (p == NULL) {
printf("當前隊列中無進程\n");
return;
}
printf("進程名 優先級 時間片 cpu時間 需要時間 進程狀態 計數器\n");
while (p != NULL) {
printf("%s %4d %4d %4d %4d %c %4d\n",p->name,p->priority,p->time_slice,p->cpu_time,p->need_time,p->state,p->time_count);
p = p->next;
}
printf("\n");
}
//優先級調度算法
void priority_scheduling(PCB *running_list){
//將隊列按優先級大小進行排序
sort(running_list);
//遍歷整個鏈表依次執行進程
PCB *s = running_list->next;
while (s != NULL) {
s->cpu_time = 1;
s->time_count = 1;
s->state = process_type_finish;
s = s->next;
set_ready(running_list);
//每執行完依次進程展示當前隊列狀況
show(running_list);
}
}
//按優先級大小對隊列進行排序
void sort(PCB *running_list){
PCB *s = running_list->next;
PCB *p = s->next;
if (s == NULL || p == NULL) {
//此時鏈表中只有0或1個結點,無須排序
return;
}
//將鏈表從第一個結點往後斷開
s->next = NULL;
//頭指針
PCB *first = running_list;
while (p != NULL) {
s = p;
p = p->next;
//將s插入斷開的新鏈表中
PCB *q = first;
//遍歷新鏈表,找到插入位置
while (q->next !=NULL) {
//判斷s結點的優先級是否比當前節點小
if (s->priority < q->next->priority) {
//是,往後繼續尋找
q = q->next;
}else{
//否,就在這裏插入
s->next = q->next;
q->next = s;
break;
}
}
if (q->next == NULL) {
//比之前的優先級都低,插入最後
q->next = s;
s->next = NULL;
}
}
}
//找到當前未執行的優先級最高的進程,將它狀態變爲就緒
void set_ready(PCB *running_list){
PCB *s = running_list->next;
if (s == NULL) {
printf("當前隊列已空\n");
return;
}
/*
該方法只適用於排序之後
// while (s != NULL && s->state != process_type_waitting) {
// s = s->next;
// }
// if (s != NULL) {
// s->state = process_type_ready;
// }
*/
//記錄當前優先級的最大值
int max = 0;
//記錄該值對應的進程
PCB *p = NULL;
while (s != NULL) {
//當該進程不屬於等待狀態時,直接跳過
if (s->state != process_type_waitting) {
s = s->next;
continue;
}
//記錄處於等待狀態的進程優先級的最大值
if (s->priority >= max) {
max = s->priority;
p = s;
}
s = s->next;
}
//P爲空說明當前已經沒有等待中的進程了
if (p != NULL) {
p->state = process_type_ready;
}
}
Main.c
//
// main.c
// ProcessSchedulingTest
//
// Created by Apple on 2019/10/21.
// Copyright © 2019 Yao YongXin. All rights reserved.
//
#include "ProcessScheduling.h"
int main(int argc, const char * argv[]) {
//運行(就緒)隊列(頭結點不儲存信息)
PCB *running_list = (PCB *)malloc(sizeof(PCB));
running_list->next = NULL;
int p_number;
printf("請輸入要創建的進程數目:\n");
scanf("%d",&p_number);
// 隨機數生成優先級
// printf("請輸入進程名字和所需時間:\n");
// for (int i = 0; i < p_number; i++) {
// //create(running_list);
// char *name = (char *)malloc(sizeof(char));
// int time;
// scanf("%s %d",name,&time);
// create_process(running_list, name, time);
// }
printf("請輸入進程名字和所需時間、優先級:\n");
for (int i = 0; i < p_number; i++) {
//create(running_list);
char *name = (char *)malloc(sizeof(char));
int time,priority;
scanf("%s %d %d",name,&time,&priority);
create_process1(running_list, name, time,priority);
}
//優先級調度法
set_ready(running_list);
printf("調度前:\n");
show(running_list);
printf("調度後:\n");
priority_scheduling(running_list);
return 0;
}
結果截圖