作業系統學習筆記之初識程式和程式控制

Chorer發表於2020-03-17

作業系統學習筆記之初識程式和程式控制

作業系統學習筆記-1:基礎概念 中,我們介紹了與作業系統相關的一些概念,在 作業系統學習筆記-2:體系結構設計和執行機制 中,我們又介紹了作業系統的結構設計和執行機制,從這篇筆記開始,我們會逐一講解作業系統的各個基本功能。

一切圍繞這張圖來進行:

作業系統學習筆記之初識程式和程式控制

1. 關於程式

1.1 程式:

為了方便作業系統管理,對併發執行的各個程式加以控制和描述,引入了程式的概念。

1.2 PCB:

定義:

之前的單道批處理系統,程式是序列執行的,記憶體中可能只需要記錄單一程式的程度段和資料段即可;但是現在使用的是多道批處理系統,多個程式併發執行,記憶體中就可能存在多個程式自己的程式段和資料段,那麼這時候就需要一個管理單元對這些東西加以區分、描述和管理,所以就額外多了一個程式控制塊,也就是 PCB(process control block)。

系統會為每一個執行的程式分配 PCB 這麼一個資料結構,用以描述程式的各種資訊。PCB 是程式存在的唯一標誌,程式與 PCB 是一一對應的的。

PCB 記錄了關於程式的資訊,這些資訊包括:

  • 程式識別符號:外部內部各一個
  • 處理機狀態:通用暫存器、指令計數器、程式狀態字 PSW,使用者棧指標
  • 程式排程資訊:程式狀態、程式優先順序、其它的程式排程資訊
  • 程式控制資訊:程式和資料的地址、程式同步和通訊機制、資源清單、連結指標

1.3 程式實體:

程式段(程式程式碼)、資料段(變數、常量等),PCB(相關的管理資訊) 共同構成了程式實體(程式映像)。一般認為 程式實體 === 程式 === PCB

PS:下文提到的多個程式的組織方式,也可以說就是多個 PCB 的組織方式

1.4 程式與程式的對比:

  • 程式是動態的(程式的執行),程式是靜態的(有序程式碼的集合)
  • 程式是暫時的,程式是永久的
  • 程式和程式的組成不同
  • 通過多次執行,一個程式可以對應多個程式;通過呼叫關係,一個程式可以包括多個程式

2. 程式的組成和組織

2.1 單個程式的組成

  • 程式描述資訊:程式識別符號PID(區分不同程式)使用者識別符號 UID(區分不同使用者)
  • 程式控制和管理資訊:程式當前狀態、程式優先順序
  • 資源分配清單:程式段指標、資料段指標、鍵鼠
  • 處理機相關資訊:各種暫存器的值

2.2 多個程式的組織方式

連結方式:

按照程式狀態將 PCB 分為多個佇列,OS 持有指向各個佇列的指標(執行指標、就緒佇列指標、阻塞佇列指標)

作業系統學習筆記之初識程式和程式控制

索引(線性)方式:

按照程式狀態建立幾張索引表,OS 持有指向各個索引表的指標(執行指標、就緒表指標、阻塞表指標)

作業系統學習筆記之初識程式和程式控制

3. 程式的特徵

  • 動態性:程式是程式的一次執行過程,是動態地產生、變化和消亡的
  • 併發性:記憶體中有多個程式實體,各個程式可以併發執行
  • 獨立性:程式是系統進行資源分配和排程的一個獨立單位
  • 非同步性:各個程式以獨立的、不可預知的速度推進
  • 結構性:每個程式都有一個自己的 PCB,程式由程度段、資料段、PCB 構成

4. 程式的狀態/生命週期

4.1 五種基本狀態:

**① 建立態:**初始化 PCB,為程式分配系統資源

**② 就緒態:**PCB 修改相應內容並被送到就緒佇列。萬事俱備(執行需要的條件都有了),只欠東風(只等 CPU 排程自己)

③ 執行態: PCB 修改相應內容,出隊(可能還會恢復程式執行環境)。該程式此時佔有 CPU 使用權,在 CPU 上執行(對於單核處理器,一個時刻只會有一個程式)

**④ 阻塞態(等待態):**程式進行系統呼叫,或者等待事件發生時,進入阻塞態,PCB 修改相應內容並被送到相應事件的阻塞佇列

**⑤ 終止態(結束態):**回收為程式分配的資源,撤銷 PCB

PS:由於事件有多個,所以阻塞佇列一般也是有多個的,一個事件對應一個阻塞佇列。而就緒佇列就只有一個了。

4.2 程式狀態的轉換:

作業系統學習筆記之初識程式和程式控制

4.3 引入掛起操作後

(1)掛起:

前面所說的狀態轉換,是建立在記憶體資源夠用的情況下 —— 當系統資源尤其是記憶體資源不夠時,就需要將一些程式掛起(suspend),對換到外存中。

(2)原因:

引起程式掛起的原因是多樣的,主要有:

  • 系統中的程式均處於阻塞態,處理器空閒,此時需要把一些阻塞程式對換出去,以騰出足夠的記憶體裝入就緒程式執行。

  • 程式競爭資源,導致系統資源不足,負荷過重,此時需要掛起部分程式以調整系統負荷,保證系統的實時性或讓系統正常執行。

  • 把一些定期執行的程式(如審計程式、監控程式、記賬程式)對換出去,以減輕系統負荷

  • 使用者要求掛起自己的程式,以便根據中間執行情況和中間結果進行某些除錯、檢查和改正。

  • 父程式要求掛起自己的後代程式,以進行某些檢查和改正。

  • 作業系統需要掛起某些程式,檢查執行中資源使用情況,以改善系統效能;或當系統出現故障或某些功能受到破壞時,需要掛起某些程式以排除故障。

(3)狀態轉換

引入掛起操作後,在原來五種狀態的基礎上多了兩個狀態:就緒態變成了活動就緒態,且多了一個“靜止就緒態/掛起就緒態“;原來的阻塞態變成了活動阻塞態,且多了一個“靜止阻塞態/掛起阻塞態“。

作業系統學習筆記之初識程式和程式控制

狀態 解釋
活動就緒態 → 靜止就緒態 作業系統根據當前資源狀況和效能要求,可能會把活動就緒態對換出去,成為靜止就緒態。處於靜止就緒態的程式不再被排程執行
靜止就緒態 → 活動就緒態 記憶體中沒有程式處於活動就緒態,或者處於靜止就緒態的程式具有更高的優先順序,那麼靜止就緒態就會被對換回來,此時才可能被排程執行
活動阻塞態→ 靜止阻塞態 作業系統根據當前資源狀況和效能要求,可能會把活動阻塞態對換出去,成為靜止阻塞態。
靜止阻塞態→ 靜止就緒態 常見的情況是,引起程式等待的事件發生之後,相應的靜止阻塞態程式將轉換為靜止就緒態
靜止阻塞態→ 活動阻塞態 但有時候,如果靜止阻塞態程式的優先順序高於靜止就緒佇列中的任何程式、並且系統有把握它等待的事件即將完成,那麼就會啟用為活動阻塞態
執行態→ 靜止就緒態 優先順序較高的靜止阻塞態在等待的事件完成後,可能會搶佔 CPU,若此時資源不夠,則可能導致正在執行的程式掛起為靜止就緒態
建立態→ 靜止就緒態 作業系統根據當前資源狀況和效能要求,可能會在程式建立完就把它對換到外存

PS:程式一旦被掛起,就意味著它被對換到了外存中,此時該程式無法再被 CPU 直接排程,除非它被對換回記憶體中,回到活動就緒態。比如靜止就緒態、靜止阻塞態,最後要得到 CPU 的排程,都必須經歷迴歸到活動就緒態的過程。

那麼一個狀態具體是如何切換到另一個狀態的呢?

5. 程式的控制

在前面我們已經說過,程式的生命週期有多個狀態,而狀態的切換實質上是通過修改 PCB 的資訊、讓 PCB 出隊或者入隊來實現的,但是是誰來控制這個過程呢?—— 答案就是程式控制,程式控制指的是對系統中所有程式,從建立到終止的全過程實行的管理和控制。而程式控制是通過作業系統核心的 原語操作 來實現的。

作業系統學習筆記之初識程式和程式控制
作業系統核心一覽,其中一個核心就是原語操作

原語(Primitive)其實就是程式 —— 由若干條機器指令構成,用以完成特定功能的一段程式。原語操作屬於原子操作(Atomic operation),具有不可中斷性,一旦執行就不允許被打斷。這種原子操作是依靠關中斷指令實現的,在關中斷指令下,即使有中斷訊號發射過來,也不會呼叫中斷處理程式去處理中斷,這就保證了原語操作不會被打斷。而在開中斷指令下,才會去處理中斷。

原語的基本操作無非三個:

  • 更新 PCB 中的資訊(修改程式狀態標誌、儲存當前執行環境到 PCB、從 PCB 中恢復執行環境)
  • 將 PCB 插入到合適的佇列
  • 分配/回收資源

建立原語和撤銷原語配對,阻塞原語和喚醒原語配對,所以這裡我們放在一起講。

(1)建立原語

建立原語負責建立程式,具體包括:申請空白的 PCB,為新程式分配所需資源、初始化 PCB、將 PCB 插入到就緒佇列。

引起程式建立的事件一般有四種:

  • 使用者登入:分時系統中,使用者登入成功,系統會為其建立一個新的程式
  • 作業排程:多道批處理系統中,從作業佇列取出作業放入記憶體時,會為其建立一個新的程式
  • 提供服務:使用者向作業系統請求服務時,會建立一個程式來處理請求
  • 應用請求:應用/使用者程式主動請求建立一個子程式

(2)撤銷原語

撤銷程式負責終止程式,具體包括:從 PCB 集合中找到終止程式的 PCB,如果程式正在執行,則立即將它的 CPU 使用權移交給其它程式。接著終止它的所有子程式,將該程式的資源還給父程式或者作業系統,最後再刪除 PCB。

引起程式終止的事件一般有三類:

  • 正常結束
  • 異常結束
  • 外界干預

(3)阻塞原語

阻塞原語負責讓程式從執行態轉換到阻塞態,具體包括:找到要阻塞的程式的 PCB,儲存當前執行環境到 PCB(方便後續恢復),修改 PCB 狀態資訊。接著暫停程式的執行,將 PCB 插入相應事件的等待佇列

引起程式阻塞的事件一般是:

  • 等待系統分配資源
  • 請求系統某些服務(比如列印服務)
  • 啟動某種操作(比如 I/O 操作)
  • 新資料尚未到達
  • 無新工作可做

注意:前面我們說過,程式從執行態切換到阻塞態,是一個主動的過程,這個主動體現在是程式自己呼叫了阻塞原語

(4)喚醒原語

喚醒原語負責讓阻塞的程式重新回到就緒態,具體包括:在事件等待佇列中找到 PCB,讓他出隊,修改 PCB 的狀態資訊,再將 PCB 插入到就緒佇列,等待 CPU 對他進行排程

一般在等待的事件發生時,程式就會被喚醒。

注意:前面我們說過,程式從阻塞態切換到執行態,是一個被動的過程,這個被動體現在並不是程式自己呼叫了喚醒原語,而是“合作”程式進行了呼叫(比如說 I/O 程式)

(5)切換原語

前面的原語主要都是操作一個程式,而切換原語同時操作到了兩個程式。

切換原語負責讓當前執行的程式從 A 切換為 B,具體包括:

  • 一方面,將 A 的執行環境儲存到 PCB 中,再將其 PCB 移入到相應的佇列(如果當前程式是從執行態到阻塞態,那麼就進入等待佇列;如果是從執行態到就緒態,那麼就進入就緒佇列)

  • 另一方面,選擇 B 程式執行,更新其 PCB,同時可能會恢復其執行環境(考慮到 B 程式此前可能曾處於阻塞態)

引起程式切換的事件一般有四種:

  • 當前程式的時間片被消耗完
  • 有更高優先順序的程式到達,搶佔了當前程式正在使用的 CPU
  • 當前程式主動阻塞
  • 當前程式終止

(6)掛起原語和啟用原語

掛起原語:

將程式從記憶體對換到外存,具體包括:找到需要掛起的程式的 PCB,檢查它的狀態並做相應操作(執行態、活動就緒態 ——> 靜止就緒態,活動阻塞態 ——> 靜止阻塞態),之後將該 PCB 複製到指定的記憶體區域。

引起程式掛起的事件,比如,使用者程式請求將自己掛起,或父程式請求將自己的某個子程式掛起

啟用原語:

將程式從外存對換回記憶體,檢查該程式的現行狀態並進行相應操作(靜止就緒態——>活動就緒態,靜止阻塞 ——> 活動阻塞態)。引起程式啟用的事件,比如,父程式或使用者程式請求啟用指定程式,或者是某個程式駐留在外存而記憶體中已有足夠的空間

參考:

程式的狀態轉換

相關文章