進行概念詳解 多執行緒上篇(二)
作業系統是程式與硬體互動的中間層,現代作業系統將程式的一次執行抽象為程序和執行緒的概念。
程序作為資源分配的基本單位,執行緒作為執行的基本單位。
程序和執行緒其實就是作業系統程式本身實現控制一個程式執行的資料項描述
所有的程式都是面向語言進行開發的,而語言本身是面向作業系統的,執行緒是作業系統對程式一次執行的抽象
所以,所有的多執行緒程式設計模型,必然遵從作業系統的大邏輯,必然是符合作業系統的對執行緒的抽象概念,作業系統在抽象之上提供了API供應用程式呼叫
簡言之,應用程式的底層是藉助於作業系統來完成多執行緒程式設計模型的,所以怎麼可能逾越系統這一根本?
本篇對作業系統中執行緒程序相關概念進行簡單介紹
程序
在很久很久之前的序列執行時,程式按順序載入到計算機中並執行,程式獨佔計算機的所有資源
程式具有順序性,封閉性和可重現性
多道程式出現之後,程式需要併發的執行,計算機的資源是共享的,而不再是某一程式執行後獨享
所以不再是順序的,而是間斷的,也不再是封閉,也不再具有可重現性
還是以做飯為例,當只有你一個人使用廚房時,你可以隨便;
但是當多個人共享時,如果你還把你自己切了一半的菜扔到那邊,可能會被扔掉,可能會被用掉,當然也可能沒事。
為了解決程式併發執行的問題,程序的概念被抽象出來,其實就相當於“一個廚房使用規章”被制定出來
所以說程序和執行緒就是作業系統用來管理維護一個程式的運行於切換而設計出來的一個概念,然後通過各種資料結構以及值等實現描繪出來
程序實體
一個程式的執行主要下面幾個部分的資料
- 程序本身的資訊(現在誰在用廚房?現在盆盆罐罐都被你放了什麼?)
- 可執行的程式碼是哪些?(菜譜步驟是什麼?)
- 程式執行所需要的資料是什麼?(食材是什麼?佐料又是什麼?)
程式段、資料段、PCB(Process Control Block)三部分構成了程序實體
程序特徵
程式的併發執行與之前的序列順序執行有了很大的變化,主要有下面幾個特徵
- 動態性
- 併發性
- 獨立性
- 非同步性
程序狀態
基本狀態
多人輪流使用廚房時,某一時刻的你到底是做完飯了?還是還在排隊?還是正在做?你會有一個狀態用來表述你現在的這種情況
對於程序也有狀態的概念
最基本的狀態包括:
- 建立
- 就緒
- 執行
- 阻塞
- 終止
其中核心是:就緒、執行、阻塞
基本的狀態切換如下
狀態轉變簡介:
程序建立後,會建立PCB,以及相關的必須資訊,然後就進入就緒狀態,等待CPU的排程
一旦CPU對該程序排程執行,也就是該程序獲得了時間片,那麼就會進行執行
當時間片用完之後,如果任務還沒有結束,那麼就需要繼續等待(比如你做飯需要5小時,然而每個人只允許2小時,如果2小時你做不完,你必須讓別人先做,你重新排隊來)
如果一個正在執行的程式遇到了IO請求,這通常是比較耗時的,程序會進入阻塞狀態
進入阻塞狀態的程序一旦獲得了想要的結果,比如IO完成,那麼就再次進入就緒狀態,等待CPU的臨幸
掛起狀態
有些系統中,還會有掛起狀態,可能系統需要讓正在執行的程式暫停下來,也可能是資源不足了,將某些不重要的程序暫停。
掛起是更徹底的暫停,可以認為掛起是“暫時被淘汰出記憶體的程序”
阻塞狀態獲得資源後會進入就緒狀態,而一旦掛起,除非解除這個狀態,否則他將一直暫停,被丟擲執行之外
阻塞是因為某些原因暫時不能被執行,掛起是直接將你暫停
當你做飯時等待水燒開,這就是阻塞,而如果是老大說我們幾個人先來,於是他們幾個輪流使用,然後你站門口看著,這就是掛起
包含掛起狀態的系統基本情況如上圖所示
就緒狀態掛起後稱之為靜態就緒,阻塞狀態掛起後稱之為靜態阻塞,掛起後的狀態不能夠直接轉換到執行狀態
活動狀態經過掛起轉換為靜止狀態,靜止狀態經過啟用轉換為活動狀態
活動就緒與靜止就緒通過掛起和啟用轉換;活動阻塞與靜止阻塞通過掛起和啟用轉換;
活動就緒的狀態經過程序排程獲得CPU時間片,進入執行狀態,執行狀態遇到請求IO等阻塞操作進入活動阻塞狀態,活動阻塞狀態IO完成將會進入活動就緒狀態,繼續等待被CPU臨幸,如上圖藍色三角區域
看起來複雜其實也很好理解,前提是要理解掛起的含義
比如資源不充足時,將一些不重要的程序暫時掛起,掛起是真正的暫停執行,是一種主動式的管理,阻塞則是被動的,掛起也意味著置換到外存中,而不是記憶體中
不管是活動阻塞還是活動就緒,他們都在記憶體中,具備了相關條件,IO完成或者獲得CPU時間片,就可以進行執行
掛起(靜止)狀態,靜止阻塞還是靜止就緒,他們都是外存中,並不能夠執行,他們還需要一個載入到記憶體的過程
一個靜止阻塞的狀態就相當於在外存中等待一個事件的完成,事件完成後,進入靜止就緒狀態,他此時還是不會得到CPU的排程,啟用後才有機會得到CPU臨幸
存在掛起狀態的系統,經過建立後,可能進入活動就緒,也可能進入靜止就緒,並不是一定進入活動就緒,然後再被掛起
在當前系統的效能和記憶體的容量均允許的情況下,完成對程序建立的必要操作後,相應的系統程序將程序的狀態轉換為活動就緒狀態
考慮到系統當前資源狀況和效能要求,並不分配給新建程序所需資源,主要是主存資源,相應的系統程序將程序狀態轉為靜止就緒狀態
終止狀態的轉換
終止狀態通常是從執行狀態進行轉換,一般情況下不管一個什麼狀態的執行緒,他只有被執行時,才會可能進入終止狀態
但是,在某些系統中,父程序有權利終止一個子程序,所以說這種情況下,就可能從阻塞或者就緒直接轉換為終止狀態
程序控制塊
程序是對於程式執行的抽象描述,那麼程序控制塊,這個對程序的描述,就相當於程序的元資料,用於描述程序本身
儘管實現很複雜,但是我們應該想象得到,作業系統核心都是C/C++,畢竟也只是一種程式語言,程式語言對於抽象概念的描述也只能是通過語言本身
所以說,他就是一個數據結構,記錄了用於控制管理程序的各個資料項。
“PCB 中記錄了作業系統所需的、用於描述程序的當前情況以及控制程序執行的全部資訊。
程序控制塊的作用是使一個在多道程式環境下不能獨立執行的程式(含資料),成為一個能獨立執行的基本單位,一個能與其它程序併發執行的程序。
或者說 , OS是根據 PCB來對併發執行的程序進行控制和管理的
例如,當OS要排程某程序執行時,要從該程序的 PCB 中查出其現行狀態及優先順序;
在排程到某程序後,要根據其 PCB 中所儲存的處理機狀態信 息,設定該程序恢復執行的現場,並根據其 PCB 中的程式和資料的記憶體始址,找到其程式 和資料;
程序在執行過程中,當需要和與之合作的程序實現同步、通訊或訪問檔案時,也 都需要訪問 PCB;
當程序由於某種原因而暫停執行時,又須將其斷點的處理機環境儲存在 PCB中。
可見,在程序的整個生命期中,系統總是通過 PCB對程序進行控制的,亦即,系 統是根據程序的PCB而不是任何別的什麼而感知到該程序的存在的。
所以說, PCB是程序 存在的惟一標誌 。 ”《計算機作業系統 第三版》
程序控制塊主要包括:
- 程序識別符號
- 計算機狀態
- 程序排程資訊
- 程序控制資訊
程序用來管理程式執行,對於一個執行中的程式總歸要有個名字,這就是程序識別符號;
計算機執行時各個硬體裝置暫存器儲存的值就是計算機的狀態(如同做飯時廚房盆盆罐罐裡面的東西);
程序有狀態,這些狀態資訊主要用來進行排程,也就是安排任務需要的資訊(可能你長得好看,就能多一次機會使用廚房);
另外還有一些對程序的控制,比如程序(執行緒)同步資料、程式地址等
在一個系統中,通常可擁有數十個、 數百個乃至數千個 PCB。
為了能對它們加以有效的管理,應該用適當的方式將這些PCB組織起來。目前常用的組織方式有以下兩種。
三座大山
程序作為作業系統對程式一次執行的抽象描述
程序的基本資訊相當於元資料,就好像表結構一樣以及一些必備的資料結構
對於程序的掌控主要有三座大山:
程序控制、程序同步、程序通訊
程序控制:
一個程序從無到有,需要建立,建立之後因為排程而執行,因為撤銷而消亡,需要有人管理他們,程序基本資訊比如PCB從哪裡來?都需要有人去做,這部分工作被稱為程序控制
程序同步:
多程序併發執行,必然可能會出現竟態,比如同時訪問某個共享資源,一個印表機不能同時列印語文和數學,所以必須做好順序的排程,這部分的工作被稱之為程序同步
程序通訊:
多程序併發執行,如何進行程序間的聯絡,如何傳遞資料?不同計算機中的兩個程序又是如何進行資料互動?這部分工作被稱之為程序通訊
如果一個員工是一個程序,程序控制相當於人事、財務部門,負責招聘薪資考勤等。
程序同步相當於專案經理,負責專案中各人員的任務分配排程。
程序通訊就相當於一種工作方式、溝通形式,比如你給我一個SVN標籤號並且告知我意圖,我去庫中檢索指定標籤修改的指定內容,就完成了一個任務的協作。
比喻或許不足夠恰當,僅供個人理解。
總結
程序作為作業系統對程式執行的抽象,那麼就使用了足夠多的資料項對程序進行描述,所有的資訊都是為了程序的管理、維護、排程、切換等
就比如你用一個數組以及一個棧頂標記來描述一個堆疊,如下圖所示
陣列a[]以及變數top就是使用陣列對棧這種資料結構進行抽象描述的資料項,對於資料元素操作訪問(入棧、出棧)限制就是規則
程序看似複雜,原理也是如此,作業系統使用多個數據項(資料結構)對程式的執行進行描述,然後定義了一整套的操作邏輯與規則
這就是我們現在學習的程序的執行原理
通過編碼將設計思路以及執行規則從抽象到具體資料結構以及編碼的實現就完成了程序的實現。
作業系統想要管理程式的執行,需要指定一個唯一的識別符號,既然放一群羊,還想對羊進行合理的管理識別,最簡單的辦法就是每隻羊掛個項圈寫上序號。
程序有狀態資訊,作業系統負責管理狀態的切換,那麼必然需要記錄程序的狀態資訊
既然是輪流分配時間片,就好像去辦理業務,排隊等待一樣,但是無數個場景下都有VIP的存在,程序也是,也有優先順序的概念
計算機的程式最終會轉換為一條條的指令,每一條指令的執行都需要藉助於程式計數器,程式計數器是用於存放下一條指令所在單元的地址的地方,所以想要知道並且記住程式執行的進度位置,還需要掌握程式計數器的值
我們熟悉的x86和arm指令大多都是基於暫存器的(虛擬機器VM是基於棧)基於暫存器的架構最明顯的特徵就在於指令的執行要依賴暫存器,如同廚房的盆盆罐罐,裡面裝著執行時的狀態資料、值(好比計算1+2+3+4,1放到a暫存器,2放到b暫存器,add a,b 計算中間結果,這句純屬為了說明,具體不要較真)
想要更好地管理程序,那麼必然還會有一些統計資訊,比如某程序運行了多久等記錄統計資訊
這些重要的資訊都儲存在程序的PCB中,所以說PCB是程序概念的核心,有了PCB程式才有併發執行的能力,通常,通常情況下,建立程序指的就是建立PCB
簡言之,作業系統對程序的抽象就是對於一組資料結構以及操作這些資料結構的規則邏輯的實現。
程序的核心狀態有執行、就緒、阻塞。
就緒就是一切準備妥當,可以被執行,就差CPU時間片了,在執行過程中如果時間片用完,那麼仍舊是轉換為就緒狀態,他什麼都不差,只是被剝奪了時間片
執行狀態下,如果執行不下去了,比如需要等待IO,就會進入阻塞,阻塞必須要等到要等的事情發生才會解除阻塞,因為他差一個事件的發生和時間片,事件到達就解除阻塞,所以就差時間片了,所以轉換為就緒狀態
比如你去銀行辦業務,人家手續都帶好了在那邊排隊就是就緒,你身份證沒影印好,就得先影印好身份證再過來排隊,否則即使到你了,你也辦不成
就緒涉及到很多事情要處理,所以為了更加安全合理,有了建立的狀態,建立就是為了保障就緒是真的就緒了,也就是檢查你的確各種資料都帶齊全了
終止狀態也是類似為了更合理安排管理,結束後也有一些事情需要做,比如你把你的資料狀態或者還可能要排隊領取個什麼別的東西,這些都不需要在櫃檯了,在大廳自助或者找大堂經理就好了
程序涉及到各種資料結構,各種規則處理,所以程序很複雜,但是程序又很簡單,就好比單例模式的實現有多種方式有些比較複雜,但是邏輯上卻又很清晰,保證唯一
原文地址: 進行概念詳解 多執行緒上篇(二)