計算機操作系統實驗之進程調度(二)優先級調度法(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.下一個要執行的進程指針。

仍然使用帶頭結點的單鏈表來存儲進程隊列,已完成的進程不移出隊列,而是沉到隊列底部。

本次實驗實現的是非搶佔式的靜態優先級調度方式,優先級在進程創建時就決定好(可以由隨機數生成,也可以讓用戶自己輸入)。由於是非搶佔式的,因此每個進程只會獲得一次處理機,無論它的執行時間是多長,都要執行完後纔會調度下一個進程。

至於具體怎麼實現調度,有兩種思路:第一種是在每次調度時去查找隊列中未完成的優先級最大的進程,將它的狀態變爲完成。第二種是:先將隊列按優先級順序排序,然後再依次執行。本次實驗採用的是第二種,因此額外寫了方法,用於按優先級排序。排序的方法是:將鏈表從頭結點處斷開,依次取出首元結點後的每個結點,對鏈表進行按值(優先級的值)插入,優先級從大到小排列。

算法流程圖

img_1

全部代碼

工程圖

img_5

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;
}

結果截圖

img_1
img_2

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章