作業系統課程設計——處理機和程式排程演算法及記憶體分配回收機制

還沒有女朋友的執念發表於2021-12-02

視覺化介面

本文程式碼地址連結:

作業系統課程設計Flask後端程式碼:https://github.com/lxy764139720/OS_experiment

作業系統課程設計Vue前端程式碼:https://github.com/lxy764139720/os_experiment_vue

多道程式系統中,程式與程式之間存在同步與互斥關係。當就緒程式數大於處理機數時,需按照某種策略決定哪些程式先佔用處理機。在可變分割槽管理方式下,採用首次適應演算法實現主存空間的分配和回收。

本程式模擬實現處理機排程和記憶體分配及回收機制,並通過視覺化介面觀察程式的執行流程與情況。為了實現演算法與介面的解耦合,以及繪製更加優美的介面,本實驗設計了前後端分離的架構,在後端使用Python的Flask框架實現相關演算法並設計通訊介面,在前端使用Vue.js框架及Element UI實現視覺化介面,前後端通過Axios框架進行通訊。


起步

1. clone git倉庫

git clone https://github.com/lxy764139720/OS_experiment
git clone https://github.com/lxy764139720/os_experiment_vue

2. 安裝環境

pip install flask
pip install flask_cors

3. 啟動後端程式

cd <PREFIX_PATH>/OS_experiment
python app.py

4. 啟動前端程式

cd <PREFIX_PATH>/os_experiment_vue
npm install
npm run serve

5. 開啟頁面 http://localhost:8080/

功能

為了實現對處理機排程演算法和記憶體分配回收演算法的模擬,本程式允許使用者進行如下操作:建立程式、掛起/解掛程式、執行程式、重新整理。

此外,使用者可以通過前端介面實時檢視每個操作帶來的效果:全部程式資訊表、記憶體分割槽表、處理機中的程式佇列、後備佇列、掛起佇列、程式的前驅後繼圖。

使用

1. 建立程式

建立程式需要使用者輸入所需時間、所需記憶體,選擇優先順序、程式屬性和前驅程式。

前驅程式的選擇會根據程式屬性自動切換是否禁用,選擇同步程式時可以選擇多項已有程式作為前驅程式。

程式資訊填寫不完整,或記憶體超出主存空間的最大容量時,會進行相應報錯提示。

選擇同步程式但為選擇前驅程式時,會自動將程式切換為獨立程式,並顯示提示資訊。

建立程式

2. 掛起/解掛程式

掛起/解掛程式分頁分為兩列,左邊為未掛起程式列表,右邊為掛起程式列表。

可以多選程式並點選下方箭頭進行掛起和解掛操作。

已經結束的程式不會出現在列表中。

掛起/解掛程式

3. 重新整理/執行

模擬程式執行一個時間單位。

4. 檢視記憶體

記憶體空間分頁中展示了當前所有的記憶體分割槽表,其中程式號-1表示作業系統佔用記憶體,用橘黃色表示,-2表示未分配記憶體用綠色表示。

通過修改後端的 Cofig.py 配置檔案,可以很方便的改變記憶體大小。

檢視記憶體

5. 檢視處理機

處理機分頁中顯示了所有處理機中分配的程式號,這些程式都處於記憶體中的活動就緒狀態,可以直接執行。

檢視處理機

通過修改後端的 Cofig.py 配置檔案,可以很方便的改變處理機的個數,下圖所示為5臺處理機分配三個程式時的情況。

修改處理機

6. 檢視後備佇列

後備佇列分頁中顯示了當前因記憶體空間不足,無法置入記憶體執行的程式號。

7. 檢視掛起佇列

掛起佇列分頁中顯示了掛起佇列中的程式情況。

結構

結構圖1

本程式為程式設計了六種狀態模型:共有<CREATE: 0>、<ACTIVE_READY: 1>、<STATIC_READY: 2>、<RUNNING: 3>、<SUSPENDING: 4>、<EXIT: 5>六種狀態;兩種屬性:< INDEPENDENT: 0>、< SYNCHRONIZED: 1>。

程式為處於活動就緒狀態、掛起狀態和靜止就緒狀態的程式分別設定了就緒佇列、掛起佇列和後備佇列,按先進先出的順序儲存程式的程式號。

另外設定一個程式佇列儲存所有的程式物件,以便根據程式號獲取程式物件。

結構圖2

程式排程流程

1. 程式建立

  • 【輸入】 程式的執行時間,所需記憶體空間,優先權,狀態,屬性(,前驅)

  • 【限制】 程式所需記憶體空間不能超過總記憶體空間減去作業系統所需的記憶體空間

  • 對全部程式佇列末尾的程式號+1獲取新程式的程式號,設定狀態為程式建立,初始化程式PCB並加入全部程式佇列的隊尾

  • 為之前的所有程式設定後繼程式

  • 檢查可分配記憶體空間,決定程式進入後備佇列或就緒佇列

  • 如果可分配記憶體空間足夠,按首次適應演算法將程式插入記憶體(就緒佇列),併為就緒佇列中的所有程式分配處理機

  • 如果可分配記憶體空間不足,將程式加入到後備佇列的隊尾

2. 程式掛起

  • 對處於活動就緒(記憶體中)的程式,從處理機的程式佇列中移出程式,釋放記憶體空間,合併未分配的記憶體空間,為就緒佇列中的所有程式重新分配處理機

  • 對於處於靜止就緒(後備佇列中)狀態的程式,從後備佇列中移出程式

  • 加入到掛起佇列的隊尾

  • 改變程式狀態為靜止就緒

3. 程式解掛

  • 從掛起佇列中移除程式

  • 檢查可分配記憶體空間,決定程式進入後備佇列或就緒佇列

  • 如果可分配記憶體空間足夠,按首次適應演算法將程式插入記憶體(就緒佇列),併為就緒佇列中的所有程式分配處理機

  • 如果可分配記憶體空間不足,將程式加入到後備佇列的隊尾

4. 程式執行

  • 檢查主存空間和處理機上是否有可執行程式

  • 執行所有處理機上的第一個程式

  • 根據可分配主存空間的大小,自動將後備佇列中的程式移入主存,同時重新為就緒佇列中的所有程式分配處理機

5. 程式結束

  • 程式執行後,若所需時間為0,則設定狀態為程式結束

記憶體排程演算法——記憶體空間首次適應分配

程式中管理記憶體空間的類包含兩個屬性:就緒佇列和記憶體分割槽表。

就緒佇列中儲存所有處於記憶體空間中的程式號,記憶體分割槽表中以[PID, 起址, 長度, 狀態]的形式儲存記憶體塊,並按起始地址進行升序排序。

記憶體分割槽表中對應儲存的PID,OS對應的記憶體表項用-1表示,未分配記憶體表項用-2表示;狀態有<UNASSIGNED: 0>、<ASSIGNED: 1>、<OS_ASSIGNED: 2>三種。

1. 檢查是否可分配記憶體空間

對於給定的程式,從記憶體分割槽表中依次查詢,如果找到一塊未分配記憶體並且該記憶體塊的大小大於等於程式所需的記憶體,就返回對應記憶體塊的序號,否則返回-1。

2. 分配記憶體空間

  • 首先檢查是否可分配記憶體空間,獲取可分配記憶體塊的序號

  • 如果該塊記憶體與程式所需記憶體的大小恰好相等,直接將該塊記憶體的程式號改為該程式的程式號,狀態設定為已分配

  • 如果該塊記憶體小於程式所需記憶體的大小,則在其後面插入一個未分割槽記憶體塊,新記憶體塊的起始地址為上一記憶體的起始地址加上程式所需記憶體大小,大小為上一記憶體的大小減去程式所需記憶體大小。將上一記憶體塊的程式號、記憶體塊大小和狀態改為該程式的程式號、記憶體大小和已分配

3. 從主存空間中移除程式

  • 首先從處理機中移除程式

  • 遍歷記憶體分割槽表,找到程式對應儲存的記憶體塊的序號

  • 將該記憶體塊的程式號設定為-2,狀態設定為未分配

  • 從就緒佇列中移除程式號

  • 合併未分配記憶體空間

4. 合併未分配記憶體空間

  • 遍歷記憶體分割槽表,找到第一塊未分配的記憶體空間

  • 繼續遍歷,將緊鄰的後續未分配記憶體空間加入要合併的記憶體列表,直到下一塊記憶體空間是已分配的

  • 對於要合併的記憶體列表,從記憶體空間中依次倒序彈出(避免彈出時超過列表的最大索引),將彈出記憶體塊的大小加入找到的第一塊未分配的記憶體空間中

5. 檢查是否有可執行程式

處理機排程演算法

程式中的處理機類包含兩個屬性:處理機個數和處理機上的程式號列表。

處理機的個數通過配置檔案進行設定,處理機上的程式號列表初始化為與處理機個數相同的空列表。

處理機類與主存空間類繫結,其中的方法只能通過主存空間物件進行呼叫,相當於主存空間的內部類。

1. 處理程式執行

  • 對所有處理機進行遍歷,獲取每個處理機上的第一個程式

  • 對於該程式,判斷其是否為獨立程式、前驅程式全部完成的同步程式、前驅程式不是剛在本次執行的不同處理機中結束的同步程式這三種情況之一

  • 對於b中的判斷結果為是的程式,執行時間減少一個單位(模擬程式執行)

  • 對於b中的判斷結果為否的程式,不做操作,進入下一迴圈

  • 如果該程式執行後恰好結束,則將其從處理機中移除,並加入本輪結束的程式列表,供b中的判斷使用

2. 從處理機中移除程式

  • 在處理機程式列表中查詢該程式,如果找到,移除該位置的程式

3. 為程式分配處理機

  • 在主存空間類中構建兩個字典,一個儲存獨立程式以及前驅已經完成的同步程式,另一個儲存同步程式

  • 遍歷就緒佇列,為每個程式設定狀態為活動就緒,並根據程式屬性加入到a中設定的兩個字典中

  • 分別對兩個字典按程式優先權降序排列

  • 將兩個字典按先獨立後同步的順序合併為一個列表

  • 迴圈為每個處理機分配程式

類設計

1. PCB類

儲存程式的狀態資訊,可以設定程式狀態,新增後繼程式,執行程式。

PCB類UML圖

2. PCBQueue類

儲存所有的程式物件,可以獲取新增程式的程式號,通過程式PID獲取程式物件,新增新程式,設定某一程式的後繼程式。

PCBQueue類UML圖

3. BackupQueue類

後備佇列,可以新增程式,有可分配記憶體空間時自動移出PCB,手動移出PCB

BackupQueue類UML圖

4. HangingQueue類

掛起佇列,可以新增和移出程式

HangingQueue類UML圖

5. MainMemory類

主存空間類,可以檢查是否可分配空間,插入程式,檢查是否有可執行程式,執行程式,移除程式,合併主存空間,為處理機分配程式。

主存空間類UML圖

6. Processor類

處理機類,可以執行程式,移除程式,為處理機分配程式,其中的方法只能被MainMemory類物件呼叫,相當於其內部類。

處理機類UML圖

相關文章