計算機操作系統實驗之模擬進程管理(C語言)

這星期開始上計算機操作系統的實驗課,打算把每個實驗的內容和思路記錄一下

實驗目的

1、 理解進程的概念,明確進程和程序的區別。

2、 理解併發執行的實質。

3、 掌握進程的創建、睡眠、撤銷等進程控制方法。

實驗內容與基本要求

用C,C++等語言編寫程序,模擬實現創建新的進程;查看運行進程;換出某個進程;殺死進程等功能。

實驗報告內容

1.進程、進程控制塊等的基本原理

a.爲了能使程序併發執行,並且可以對併發執行的程序加以描述和控制,引入了“進程”的概念。它是資源分配和獨立運行的基本單位。

b.進程控制塊(PCB)是操作系統爲進程配置的一個專門的數據結構。系統利用PCB來描述進程的基本情況和活動過程,進而控制和管理進程。

進程PCB可以包含

/*
|進程ID|
|進程優先級|
|進程大小(進程執行時間|
|進程內容|
|進程狀態|
|指針|
*/

2.進程過程圖

img_1

以傳統菜單的形式呈現功能。

1.創建新的進程 2.查看運行進程”

3.換出某個進程 4.殺死運行進程”

5.喚醒某個進程 6.退出程序 “

實現思路及功能分析

系統利用進程控制塊(Process Control Block,PCB)來描述系統的基本情況和活動過程,要進行進程管理,實際上就是在操作進程的PCB。因此要求模擬進程管理,首先要模擬出PCB的結構,再實現它的創建、撤銷等操作。

一般來說,進程擁有三種基本狀態:就緒、執行、阻塞。在引入了掛起原語操作後,還會細分爲活動就緒、靜止就緒、活動阻塞、靜止阻塞。在我的理解中,活動與靜止的區別就是,活動時進程是在主存中的,而靜止時進程已經被調到了輔存裏。

在單處理機系統中,只有一個進程處於執行狀態,而在多處理機系統中,能有多個進程處於執行狀態。因此在這裏我們不將執行狀態與就緒狀態特別區分開來,只設置兩個鏈表,一個鏈表用於保存處於執行(或就緒)狀態的進程,一個鏈表用於保存處於阻塞狀態的進程。

當然,如果想模擬單處理機系統的話,也可以將處於就緒狀態鏈表的第一個結點默認設置爲執行狀態,當有優先度更高的進程時,讓它成爲執行狀態,插入鏈表頭部,原有的第一個結點轉爲就緒狀態即可。但是本實驗中不涉及優先級調度的算法,所以就簡化處理了。

同樣,我們模擬內存的大小,例如理論上可以同時運行20個進程,那麼將處於執行狀態的進程轉爲阻塞狀態時,可以看做把它轉移到了輔存中。但是不區分活動阻塞、靜止阻塞,只是簡單地設置成運行進程個數的變化。

總的來說,我們這次試驗的思路是

  • 設置兩個單鏈表,一個用於存儲運行的進程,一個用於存儲阻塞狀態的進程
  • 默認內存中可以存放最多20個進程,將處於運行隊列的進程看作在內存中,阻塞狀態不在內存中
  • 進程創建,則去申請內存空間,填寫完進程信息後直接加入運行隊列
  • 殺死進程,則將進程從運行隊列中刪除,並直接釋放
  • 進程的換出與喚醒,就是讓進程在運行隊列與阻塞隊列之間轉換(進程自己的狀態也發生改變)
  • 爲了操作簡便,額外寫了幾個輔助函數來使用

全部代碼

工程圖

img_2

ProcessControl.h

//
//  ProcessControl.h
//  ProcessControlTest
//
//  Created by Apple on 2019/10/13.
//  Copyright © 2019 Yao YongXin. All rights reserved.
//

#ifndef ProcessControl_h
#define ProcessControl_h

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

//最大內存的大小
#define MAX_SIZE 20

//線程狀態:運行(就緒)  阻塞
enum process_type{
    process_type_running = 1000,
    process_type_block = -1000,
    process_type_ready = 500
};

//進程控制塊結構體
typedef struct PCB_Type{
    //進程的id
    int pid;
    //進程的優先級
    int priority;
    //進程大小(執行時間)
    int size;
    //進程內容
    char content[20];
    //進程的狀態  執行  阻塞
    int state;
    //下一個要執行的進程
    struct PCB_Type *next;
}PCB;

//創建新的進程
void create(PCB *running_list,PCB *block_list,int *size);
//查看運行進程
void show_running(PCB *running_list);
//換出某個進程
void change(PCB *running_list,PCB *block_list,int *size);
//殺死運行進程
void killed(PCB *running_list,int *size);
//喚醒某個進程
void wake_up(PCB *running_list,PCB *block_list,int *size);

//判斷在運行(就緒)隊列中是否存在有該pid值的進程 0->不存在 1->存在
int exist_in_running(PCB *running_list,int pid);
//判斷在阻塞隊列中是否存在有該pid值的進程 0->不存在 1->存在
int exist_in_block(PCB *block_list,int pid);
//通過pid尋找進程的位置(返回其前一個結點的地址
PCB *find(PCB *list,int pid);

#endif /* ProcessControl_h */

ProcessControl.c

//
//  ProcessControl.c
//  ProcessControlTest
//
//  Created by Apple on 2019/10/13.
//  Copyright © 2019 Yao YongXin. All rights reserved.
//

#include "ProcessControl.h"

//創建新的進程
void create(PCB *running_list,PCB *block_list,int *size){
    if (*size >= MAX_SIZE) {
        //內存不足,無法創建
        printf("內存不足,無法創建新的進程\n");
        return;
    }
    //申請一個內存控制塊的空間
    PCB *p = (PCB *)malloc(sizeof(PCB));
    assert(p != NULL);
    
    //設置該控制塊的id值
    int pid;
    printf("請輸入新進程的pid:\n");
    scanf("%d",&pid);
    
    //判斷pid值是否重複
    if (exist_in_running(running_list, pid)) {
        printf("該值已存在!\n");
        return;
    }
    if (exist_in_block(block_list, pid)) {
        printf("該值已存在!\n");
        return;
    }
    //沒重複,保存
    p->pid = pid;
    
    //設置該控制塊的其他值
    printf("請輸入新進程的優先級:\n");
    scanf("%d",&p->priority);
    printf("請輸入新進程的大小:\n");
    scanf("%d",&p->size);
    printf("請輸入新進程的內容:\n");
    scanf("%s",p->content);
    p->state = process_type_running;
    p->next = NULL;
    
    //放入就緒隊列中
    PCB *s = running_list;
    while (s->next != NULL) {
        s = s->next;
    }
    s->next = p;
    
    //進程數量+1
    *size = *size + 1;
}

//查看運行進程
void show_running(PCB *running_list){
    PCB *s = running_list->next;
    if (s == NULL) {
        printf("沒有正在運行的進程\n");
        return;
    }
    
    while (s != NULL) {
        printf("進程id:%d\n",s->pid);
        printf("進程優先級:%d\n",s->priority);
        printf("進程大小:%d\n",s->size);
        printf("進程內容:%s\n",s->content);
        printf("___________\n");
        
        s = s->next;
    }
}

//換出某個進程
void change(PCB *running_list,PCB *block_list,int *size){
    if (*size == 0) {
        printf("無可換出的進程\n");
        return;
    }
    
    int pid;
    printf("請輸入需要換出進程的id:\n");
    scanf("%d",&pid);
    //查看該線程是否在就緒隊列中
    if (exist_in_running(running_list, pid)) {
        //存在,找到該線程的位置(返回的是前一個結點的地址
        PCB *s = find(running_list, pid);
        //修改線程狀態
        s->next->state = process_type_block;
        
        //將該線程存入阻塞隊列中
        //尋找插入位置
        PCB *p = block_list;
        while (p->next != NULL) {
            p = p->next;
        }
        //插入
        p->next = s->next;
        
        //將該線程從就緒隊列中移出
        s->next = s->next->next;
        
        //將該線程的next重置爲空
        p->next->next = NULL;
        
        *size = *size - 1;
        printf("成功換出\n");
    }else{
        printf("該線程不存在或已處於阻塞狀態\n");
    }
}

//殺死運行進程
void killed(PCB *running_list,int *size){
    if (*size == 0) {
        printf("無可殺死的進程\n");
        return;
    }
    
    int pid;
    printf("請輸入要殺死的進程id:\n");
    scanf("%d",&pid);
    //判斷該進程是否存在
    if (exist_in_running(running_list, pid)) {
        //存在,找到該線程的位置(返回的是前一個結點的地址
        PCB *s = find(running_list, pid);
        //將該線程從就緒隊列移出
        s->next = s->next->next;
        *size = *size - 1;
        
        //直接釋放掉該線程
        free(s);
        printf("成功殺死\n");
    }else{
        printf("該線程不存在或已處於阻塞狀態\n");
    }
}

//喚醒某個進程
void wake_up(PCB *running_list,PCB *block_list,int *size){
    PCB *s = block_list;
    if (s->next == NULL) {
        printf("沒有可喚醒的線程\n");
        return;
    }
    
    int pid;
    printf("請輸入要喚醒的進程id:\n");
    scanf("%d",&pid);
    //判斷該進程是否存在
    if (exist_in_block(block_list, pid)) {
        //存在,查找到該線程的位置(返回的是前一個結點的地址
        s = find(block_list, pid);
        //修改線程狀態
        s->next->state = process_type_running;
        
        //將該線程存入就緒隊列中
        //尋找插入位置(最後一位)
        PCB *p = running_list;
        while (p->next != NULL) {
            p = p->next;
        }
        //插入
        p->next = s->next;
        
        //將該線程從阻塞隊列中取出
        s->next = s->next->next;
        
        //將該線程的next值重置爲null
        p->next->next = NULL;
        
        *size = *size + 1;
        printf("喚醒成功\n");
    }else{
        printf("該線程不存在\n");
    }
}

//判斷在就緒隊列中是否存在有該pid值的進程 0->不存在 1->存在
int exist_in_running(PCB *running_list,int pid){
    int result = 0;
    
    PCB *s = running_list->next;
    //遍歷執行狀態的鏈表
    while (s != NULL) {
        if (s->pid == pid) {
            //存在,直接返回
            result = 1;
            break;
        }
        s = s->next;
    }
    return result;
}
//判斷在阻塞隊列中是否存在有該pid值的進程 0->不存在 1->存在
int exist_in_block(PCB *block_list,int pid){
    int result = 0;
    
    //遍歷阻塞狀態的鏈表
    PCB *s = block_list->next;
    while (s != NULL) {
        if (s->pid == pid) {
            //存在,直接返回
            result = 1;
            break;
        }
        s = s->next;
    }
    
    return result;
}

//通過pid尋找進程的位置(返回其前一個結點的地址
PCB *find(PCB *list,int pid){
    PCB *s = list;
    
    while (s->next != NULL) {
        if (s->next->pid == pid) {
            return s;
        }
        s = s->next;
    }
    
    return NULL;
}

main.c

//
//  main.c
//  ProcessControlTest
//
//  Created by Apple on 2019/10/13.
//  Copyright © 2019 Yao YongXin. All rights reserved.
//

#include "ProcessControl.h"

void showLine(){
    printf("**************************\n");
}

int main(int argc, const char * argv[]) {
    
    //運行(就緒)隊列(頭結點不儲存信息)
    PCB *running_list = (PCB *)malloc(sizeof(PCB));
    running_list->next = NULL;
    
    //阻塞隊列(頭結點不儲存信息)
    PCB *block_list = (PCB *)malloc(sizeof(PCB));
    block_list->next = NULL;
    
    //當前運行的線程數量
    int storage_number = 0;
    
    int choose = 1;
    while (choose) {
        //展示菜單
        showLine();
        printf("*     進程演示系統      *\n");
        showLine();
        printf("1.創建新的進程  2.查看運行進程\n");
        printf("3.換出某個進程  4.殺死運行進程\n");
        printf("5.喚醒某個進程  6.退出程序   \n");
        showLine();
             
        printf("請選擇(1~6):\n");
        scanf("%d",&choose);
             
        switch (choose) {
            case 1:
                //創建新的進程
                create(running_list, block_list, &storage_number);
                break;
            case 2:
                //查看運行進程
                show_running(running_list);
                break;
            case 3:
                //換出某個進程
                change(running_list, block_list, &storage_number);
                break;
            case 4:
                //殺死運行進程
                killed(running_list, &storage_number);
                break;
            case 5:
                //喚醒某個進程
                wake_up(running_list, block_list, &storage_number);
                break;
            case 6:
                return 0;
            default:
                printf("沒有這個選項!\n");
                break;
        }
             
    }
      
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章