計算機操作系統實驗一模擬進程管理(C語言)
這星期開始上計算機操作系統的實驗課,打算把每個實驗的內容和思路記錄一下
實驗目的
1、 理解進程的概念,明確進程和程序的區別。
2、 理解併發執行的實質。
3、 掌握進程的創建、睡眠、撤銷等進程控制方法。
實驗內容與基本要求
用C,C++等語言編寫程序,模擬實現創建新的進程;查看運行進程;換出某個進程;殺死進程等功能。
實驗報告內容
1.進程、進程控制塊等的基本原理
a.爲了能使程序併發執行,並且可以對併發執行的程序加以描述和控制,引入了“進程”的概念。它是資源分配和獨立運行的基本單位。
b.進程控制塊(PCB)是操作系統爲進程配置的一個專門的數據結構。系統利用PCB來描述進程的基本情況和活動過程,進而控制和管理進程。
進程PCB可以包含
/*
|進程ID|
|進程優先級|
|進程大小(進程執行時間|
|進程內容|
|進程狀態|
|指針|
*/
2.進程過程圖
以傳統菜單的形式呈現功能。
1.創建新的進程 2.查看運行進程”
3.換出某個進程 4.殺死運行進程”
5.喚醒某個進程 6.退出程序 “
實現思路及功能分析
系統利用進程控制塊(Process Control Block,PCB)來描述系統的基本情況和活動過程,要進行進程管理,實際上就是在操作進程的PCB。因此要求模擬進程管理,首先要模擬出PCB的結構,再實現它的創建、撤銷等操作。
一般來說,進程擁有三種基本狀態:就緒、執行、阻塞。在引入了掛起原語操作後,還會細分爲活動就緒、靜止就緒、活動阻塞、靜止阻塞。在我的理解中,活動與靜止的區別就是,活動時進程是在主存中的,而靜止時進程已經被調到了輔存裏。
在單處理機系統中,只有一個進程處於執行狀態,而在多處理機系統中,能有多個進程處於執行狀態。因此在這裏我們不將執行狀態與就緒狀態特別區分開來,只設置兩個鏈表,一個鏈表用於保存處於執行(或就緒)狀態的進程,一個鏈表用於保存處於阻塞狀態的進程。
當然,如果想模擬單處理機系統的話,也可以將處於就緒狀態鏈表的第一個結點默認設置爲執行狀態,當有優先度更高的進程時,讓它成爲執行狀態,插入鏈表頭部,原有的第一個結點轉爲就緒狀態即可。但是本實驗中不涉及優先級調度的算法,所以就簡化處理了。
同樣,我們模擬內存的大小,例如理論上可以同時運行20個進程,那麼將處於執行狀態的進程轉爲阻塞狀態時,可以看做把它轉移到了輔存中。但是不區分活動阻塞、靜止阻塞,只是簡單地設置成運行進程個數的變化。
總的來說,我們這次試驗的思路是
- 設置兩個單鏈表,一個用於存儲運行的進程,一個用於存儲阻塞狀態的進程
- 默認內存中可以存放最多20個進程,將處於運行隊列的進程看作在內存中,阻塞狀態不在內存中
- 進程創建,則去申請內存空間,填寫完進程信息後直接加入運行隊列
- 殺死進程,則將進程從運行隊列中刪除,並直接釋放
- 進程的換出與喚醒,就是讓進程在運行隊列與阻塞隊列之間轉換(進程自己的狀態也發生改變)
- 爲了操作簡便,額外寫了幾個輔助函數來使用
全部代碼
工程圖
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;
}