二、进程管理
??進(jìn)程是操作系統(tǒng)實(shí)現(xiàn)并發(fā)的基礎(chǔ),了解進(jìn)程才能明白操作系統(tǒng)運(yùn)行的實(shí)現(xiàn)過程。這篇文章對于進(jìn)程進(jìn)行一個(gè)討論,希望在讀完之后能對進(jìn)程有一個(gè)清晰的認(rèn)識(shí)。
??進(jìn)程概念
??對進(jìn)程概念的介紹,圍繞著這幾個(gè)問題:
????1. 為什么要進(jìn)程?
????2. 什么是進(jìn)程?
????3. 進(jìn)程由什么組成?
??1. 為什么要進(jìn)程?
??多道程序環(huán)境下,程序并發(fā)執(zhí)行。為了讓各個(gè)程序相對獨(dú)立,運(yùn)行無誤,引入進(jìn)程這個(gè)概念來對并發(fā)執(zhí)行的程序加以描述和控制(這個(gè)比較晦澀,從進(jìn)程本身角度說,程序A運(yùn)行的時(shí)候希望有一個(gè)獨(dú)立的空間不受他人干擾,進(jìn)程就提供了這個(gè)空間。從使用者的角度說,對操作系統(tǒng)引入進(jìn)程這個(gè)數(shù)據(jù)結(jié)構(gòu),能夠更清晰的表達(dá)動(dòng)態(tài)系統(tǒng)運(yùn)行的內(nèi)在規(guī)律)
??2. 什么是進(jìn)程?
??這個(gè)問題說法不一,但我覺得進(jìn)程就是運(yùn)行中的程序。這句話也側(cè)面解釋了進(jìn)程和程序之間的區(qū)別。程序是靜態(tài)的,而進(jìn)程是動(dòng)態(tài)的。除此之外,進(jìn)程內(nèi)部的內(nèi)容也更多,將在下個(gè)問題中介紹。
??3. 進(jìn)程由什么組成?
??我們常常說的進(jìn)程其實(shí)是進(jìn)程實(shí)體(進(jìn)程映像) 的簡稱,主要有程序段、相關(guān)的數(shù)據(jù)段、和PCB(下面再詳細(xì)介紹)三部分組成。這里的相關(guān)數(shù)據(jù)段包括堆、棧、數(shù)據(jù)段三類,程序段就是代碼段。
下面詳細(xì)介紹一下PCB(這可是進(jìn)程里面很重要的!)
在介紹PCB之前說一下,為啥要PCB?都知道程序分時(shí)運(yùn)行,到了時(shí)間就要換程序執(zhí)行。那不同程序之間的狀態(tài)肯定是不同的(程序A有程序A的數(shù)據(jù),程序B有程序B的數(shù)據(jù))。之前說過在兩次時(shí)間切換之間,操作系統(tǒng)會(huì)實(shí)現(xiàn)保護(hù)現(xiàn)場和恢復(fù)現(xiàn)場。那他們的依據(jù)從哪來呢?就是PCB!所以PCB就是保存進(jìn)程中各類數(shù)據(jù)信息及當(dāng)前情況的數(shù)據(jù)結(jié)構(gòu)。
??進(jìn)程控制塊PCB(process control block)
??PCB中主要包含如下四部分
??1) 進(jìn)程標(biāo)識(shí)符
??進(jìn)程標(biāo)識(shí)符的作用就是唯一的標(biāo)識(shí)一個(gè)進(jìn)程,以便于對這個(gè)進(jìn)程進(jìn)行調(diào)用。有兩種類型,針對于用戶和系統(tǒng)使用,分別是外部標(biāo)識(shí)符(用戶),內(nèi)部標(biāo)識(shí)符。編程序時(shí)fork函數(shù)返回的應(yīng)該是外部標(biāo)識(shí)符。
??2) 處理機(jī)狀態(tài)
??處理機(jī)狀態(tài)又稱處理機(jī)的上下文(還有一個(gè)概念是上下文切換,就是針對于這部分內(nèi)容的切換),主要包括各種寄存器中的內(nèi)容:通用寄存器、當(dāng)前指令地址(PC)、程序狀態(tài)字(PSW)、用戶棧指針。這部分內(nèi)容也是PCB存儲(chǔ)中最顯著的。
??3) 進(jìn)程調(diào)度信息
??進(jìn)程調(diào)度信息表明該進(jìn)程當(dāng)前的狀態(tài)(關(guān)于進(jìn)程狀態(tài)的分類稍后介紹),進(jìn)程的優(yōu)先級(jí)、用于完成調(diào)度的其他信息(還有什么?)、如果發(fā)生阻塞,存儲(chǔ)阻塞原因。學(xué)名叫事件。
??4) 進(jìn)程控制信息
??指用于進(jìn)程所必需的信息,包括本進(jìn)程程序段和數(shù)據(jù)段的地址(不一定是首地址,可能是當(dāng)前執(zhí)行的)、進(jìn)程同步和通信機(jī)制所需要的一些東西(都有哪些?),資源清單,包括總預(yù)計(jì)和當(dāng)前已分配、鏈接指針,本進(jìn)程PCB所在隊(duì)列的下一個(gè)進(jìn)程PCB的首地址(怎么理解?PCB之間的存儲(chǔ)以鏈表形式嗎?)
??如果一個(gè)進(jìn)程一個(gè)PCB的話,PCB的數(shù)量也不會(huì)少。所以需要方式進(jìn)行管理,目前常用的組織方式包括線性方式、鏈接方式、索引方式。在此不再細(xì)說,有需要可以自己去查。
??以上介紹的PCB內(nèi)容都比較基礎(chǔ),但其實(shí)PCB是一個(gè)很大的數(shù)據(jù)結(jié)構(gòu)。涉及很多方面。更為詳細(xì)的說明如下圖(我還沒學(xué)到,就先不一一介紹了):
??下面來補(bǔ)上面的坑,談?wù)勈裁词沁M(jìn)程狀態(tài)。
??進(jìn)程最基本的狀態(tài)有三種:就緒、阻塞、執(zhí)行
??就緒指進(jìn)程已經(jīng)準(zhǔn)備好了,只要獲得CPU的資源就可以運(yùn)行程序。因?yàn)樘幱诰途w狀態(tài)的進(jìn)程可能很多,所以以隊(duì)列存儲(chǔ),并配合專門的調(diào)度算法。
??執(zhí)行就是進(jìn)程正在進(jìn)行,沒啥好說的。對于單核CPU,同一時(shí)間只有一個(gè)進(jìn)程處于執(zhí)行狀態(tài)。
??阻塞指執(zhí)行狀態(tài)的進(jìn)程因某些操作(通常是I/O)而終止運(yùn)行,進(jìn)行等待。阻塞完成后會(huì)重新進(jìn)入就緒狀態(tài)。
??執(zhí)行狀態(tài)會(huì)有兩種變化方向:一種向就緒狀態(tài)(時(shí)間片到達(dá)),一種向阻塞狀態(tài)(發(fā)生I/O操作)。三者轉(zhuǎn)化關(guān)系如下圖(圖中引入新的,終止?fàn)顟B(tài)是為了使結(jié)構(gòu)完整):
??我們常常聽到一個(gè)名詞叫”掛起”,比如后臺(tái)進(jìn)程的掛起。掛起也是一種改變進(jìn)程狀態(tài)的操作。那為啥要掛起呢?原因有很多,比如這個(gè)進(jìn)程不用,通過掛起可以將這部分資源拿出來給其他的用。或者是通過掛起完成對進(jìn)程的控制(不讓運(yùn)行了)。當(dāng)引入掛起操作后,就區(qū)分出活動(dòng)和靜止兩個(gè)分類(活動(dòng)就緒,活動(dòng)阻塞,靜止就緒,靜止阻塞)。普通處于就緒狀態(tài)就叫活動(dòng)就緒,掛起后就變成了靜止就緒,普通處于阻塞狀態(tài)就叫活動(dòng)阻塞,掛起后就變成了靜止阻塞。與掛起相對的是激活操作,實(shí)現(xiàn)反向功能。當(dāng)引入創(chuàng)建狀態(tài)的時(shí)候,從創(chuàng)建狀態(tài)可以直接變成就緒狀態(tài)。如果進(jìn)程在內(nèi)存中變成活動(dòng)就緒,在磁盤中變成靜止就緒(遠(yuǎn)的就是不用,就靜止)。把所有的狀態(tài)都放在一張圖里就是下面這個(gè)樣子:
??進(jìn)程通信
??帶著問題說:
????1. 為什么需要進(jìn)程通信?
????2. 有哪幾種方式實(shí)現(xiàn)進(jìn)程通信?
??1. 為什么需要進(jìn)程通信
??關(guān)于這個(gè)問題,老師給了三種原因:
??1) 當(dāng)無法改寫應(yīng)用程序時(shí),用進(jìn)程通信去操作已有的應(yīng)用程序(怎么理解?)
??2) 完成同一個(gè)任務(wù)的多個(gè)進(jìn)程需要通信。
??3) 模塊化、方便(怎么理解?)
??實(shí)現(xiàn)進(jìn)程通信的最大目的就是數(shù)據(jù)共享,操作系統(tǒng)分時(shí)特點(diǎn),同一程序多個(gè)進(jìn)程間相互協(xié)作說白了也是為了實(shí)現(xiàn)數(shù)據(jù)共享。不過這里面的進(jìn)程通信指的是進(jìn)程間,而不是進(jìn)程內(nèi)部。
??2. 有哪幾種方式實(shí)現(xiàn)進(jìn)程通信呢?
說到通信,最容易想的方式肯定是通過文件。一個(gè)寫一個(gè)讀,只要處理好順序問題就不會(huì)有錯(cuò)。但文件讀寫也屬于I/O操作,實(shí)在太慢。所以操作系統(tǒng)額外提供了三種進(jìn)程通信的機(jī)制:消息隊(duì)列、共享內(nèi)存、管道
??1) 消息隊(duì)列
??實(shí)際上用鏈表維護(hù)了一個(gè)消息隊(duì)列,進(jìn)程具有讀或?qū)懙臋?quán)力。發(fā)方寫,再讓收方 讀。很類似于文件,但可能存放的位置不同,使用起來更快。但這里存在一個(gè)矛盾,
??隊(duì)列中每個(gè)數(shù)據(jù)多大呢?選擇定長的話易設(shè)計(jì),但不易使用。不定長相反。所以基本只用于早期系統(tǒng)。有關(guān)于消息傳遞的編程可以參考下面這個(gè)博客:進(jìn)程通信之消息隊(duì)列_我愛加菲貓-CSDN博客_進(jìn)程通信消息隊(duì)列;
??2) 共享內(nèi)存
??共享內(nèi)存就更是簡單粗暴了,既然希望共享數(shù)據(jù),直接在內(nèi)核中開辟一段空間作為共享數(shù)據(jù)區(qū)域,所有進(jìn)程都可以讀寫。因?yàn)槭窃趦?nèi)核區(qū)域,所以存取的速度比較快。也是實(shí)現(xiàn)通信的最快方式。不過哪有這么好的事兒?訪問同一區(qū)域就會(huì)遇到數(shù)相關(guān)問題(先讀后寫),所以共享內(nèi)存的使用建立在進(jìn)程同步的基礎(chǔ)之上。
??3) 管道
??消息隊(duì)列太慢,共享內(nèi)存沒有規(guī)定容易亂。管道就起一個(gè)權(quán)衡作用,集百家之所長。在內(nèi)核中開辟一段空間,以隊(duì)列方式管理,管道一端只能輸入、一段只能輸出。但管道空間有限,所以要做一些判斷:滿了不能寫,空了不能讀。管道還涉及到一些重定向的問題,我現(xiàn)在也不會(huì),就不說了(美其名曰:揚(yáng)長避短)。在目前的系統(tǒng)中,管道是用的最多的一種。
??線程
??線程這個(gè)概念,應(yīng)該聽過很多次了吧。在強(qiáng)調(diào)并行計(jì)算的時(shí)候,都會(huì)說到多線程。那線程和進(jìn)程間有什么聯(lián)系呢?簡單的總結(jié):線程是進(jìn)程的一個(gè)變種。下面來聊聊吧!
??1. 為什么需要線程?
??咱們首先來比較一下,一個(gè)程序的多個(gè)進(jìn)程間有什么異同?
??相同之處:代碼、數(shù)據(jù)一樣,權(quán)限一樣、文件資源一樣
??不同之處:每個(gè)進(jìn)程有各自的執(zhí)行狀態(tài),PC等寄存器。
??可以把相同不同分為兩個(gè)類:資源、執(zhí)行狀態(tài)。資源都相同,還為啥要每個(gè)都存一份。只要保存每個(gè)進(jìn)程各自的執(zhí)行狀態(tài)就行了呀!對嘍,這就是線程的思想。把執(zhí)行狀態(tài)取出來,就叫做線程(感覺有點(diǎn)兒像那個(gè)提取公因式,hhh)。
??下面來多說一點(diǎn)兒和線程相關(guān)的:
??之前認(rèn)為進(jìn)程是操作系統(tǒng)中最小的,但其實(shí)不是滴。線程才是處理器調(diào)度的基本單位。一個(gè)進(jìn)程可以創(chuàng)建多個(gè)線程,多個(gè)線程共享地址空間、資源,線程也有三個(gè)狀態(tài)(就緒、執(zhí)行、阻塞),操作系統(tǒng)怎么感知線程呢?和進(jìn)程一樣,進(jìn)程有PCB,線程有TCB(線程控制塊, Thread Control Block)。每一個(gè)線程都要有一個(gè)獨(dú)立的棧(共用一個(gè)會(huì)滿滴,所以不行)
??來比較下線程和進(jìn)程,它們各自都有什么優(yōu)勢呢?
??線程更快、更小。但獨(dú)立性不好(需要共用資源)。進(jìn)程就反過來了。所以不同不同需求選擇就不同,而不是說線程一定比進(jìn)程要好。舉個(gè)例子網(wǎng)頁瀏覽器多個(gè)網(wǎng)頁用的是進(jìn)程,而不是線程。為什么呢?這就是線程一個(gè)最大的(I think)缺點(diǎn):一個(gè)進(jìn)程中有多個(gè)線程,但若一個(gè)線程出錯(cuò),整個(gè)進(jìn)程被強(qiáng)迫終止。以線程管理網(wǎng)頁就會(huì)一個(gè)崩,個(gè)個(gè)崩。所以多線程編程還是多進(jìn)程編程也是看需要。
??以上常說的線程都叫做內(nèi)核級(jí)線程,是由操作系統(tǒng)內(nèi)核建立的。但有一個(gè)概念要清楚,涉及到操作系統(tǒng)內(nèi)核的操作必將需要狀態(tài)的轉(zhuǎn)換(用戶態(tài)到內(nèi)核態(tài)),這個(gè)是要花時(shí)間的。所以能在用戶態(tài)做的事情是最好的了。所以又設(shè)計(jì)了用戶級(jí)線程,管理模塊叫做utcb,分配在數(shù)據(jù)段,同時(shí)也要有獨(dú)立的棧。因?yàn)闆]有操作系統(tǒng)參與,但線程仍需要調(diào)度。所以需要自己在代碼段完成調(diào)度算法。優(yōu)點(diǎn)就是性能高,靈活(允許進(jìn)程制定屬于自己的調(diào)度算法,進(jìn)程管理靈活)。拿用戶線程和內(nèi)核線程做一個(gè)比較,如下圖:
??系統(tǒng)調(diào)用阻塞問題指用戶級(jí)線程如果調(diào)用了系統(tǒng)調(diào)用,就會(huì)引發(fā)系統(tǒng)調(diào)用阻塞。(可能是沒權(quán)利吧)。更詳細(xì)的比較可以參考:用戶級(jí)線程和內(nèi)核級(jí)線程的區(qū)別 - 知乎 (zhihu.com)
??用戶級(jí)線程的實(shí)現(xiàn)方式有多種(依舊依附于內(nèi)核級(jí)線程)。分為多對一(多用戶對應(yīng)一內(nèi)核),一對一(一用戶對應(yīng)一內(nèi)核)、多對多(多用戶對應(yīng)多內(nèi)核)。這里了解的不是很多,就不說了。
??進(jìn)程同步
??首先思考一個(gè)問題:為什么需要進(jìn)程同步?試想這樣一個(gè)場景,對于一個(gè)全局變量,很多個(gè)進(jìn)程都可以訪問并且對該變量進(jìn)行操作。結(jié)合計(jì)算機(jī)分時(shí)系統(tǒng)的特點(diǎn),那會(huì)不會(huì)出現(xiàn)不同情況下執(zhí)行結(jié)果不一致的情況。答案是會(huì)!(原因在此不做解釋,自己去查查或許印象更深)我們稱這種全局變量為臨界資源,針對于代碼中對于臨界資源的操作過程稱為臨界區(qū),針對于臨界資源產(chǎn)生的問題叫做臨界區(qū)問題。
??所以我們需要進(jìn)程同步機(jī)制來控制各個(gè)進(jìn)程對于臨界區(qū)的使用。書上對此的描述原文是:進(jìn)程同步機(jī)制的主要任務(wù),是對多個(gè)相關(guān)進(jìn)程在執(zhí)行次序上進(jìn)行協(xié)調(diào),使并發(fā)執(zhí)行的諸進(jìn)程之間按照一定規(guī)則(或時(shí)序)共享系統(tǒng)資源,并能很好地相互合作,從而使程序的執(zhí)行具有可再現(xiàn)性。
??進(jìn)程同步對于臨界區(qū)問題的解決有四個(gè)原則:空閑讓進(jìn)、忙則等待、有限等待、讓權(quán)等待。我用自己的理解簡單解釋下:
??空閑讓進(jìn):如果臨界區(qū)空閑,任何一個(gè)需要臨界區(qū)的進(jìn)程都可以使用
??忙則等待:自己想要使用臨界區(qū),但此時(shí)此刻被占用,要排隊(duì)等待,空了再用
??有限等待:等待也是有限度的,要保證進(jìn)程能夠使用到臨界區(qū)
??讓權(quán)等待:如果已經(jīng)知道沒希望了,趕緊換個(gè)進(jìn)程,別占用等待區(qū)的位置
??進(jìn)程同步只是個(gè)機(jī)制,那具體可以通過什么方法呢?老師和書一共給了三種方法:Peterson方法、硬件同步機(jī)制、信號(hào)量機(jī)制。下面一一展示下(在此不做詳細(xì)的說明,每一種方法展開說都太多,有需要的再去找對應(yīng)的內(nèi)容即可):
??Peterson方法:
??Peterson方法通過增加turn變量結(jié)合flag實(shí)現(xiàn)了進(jìn)程同步機(jī)制(對于臨界區(qū)的唯一使用,如果沖突會(huì)卡在while處)。它的優(yōu)缺點(diǎn)如下圖:
??硬件同步機(jī)制
??之所以會(huì)發(fā)生臨界區(qū)問題,就是因?yàn)榉謺r(shí)復(fù)用嘛。分時(shí)復(fù)用是操作系統(tǒng)按照時(shí)鐘中斷進(jìn)程調(diào)度。如果硬件上在每次進(jìn)入臨界區(qū)代碼前,直接關(guān)閉中斷。就不會(huì)有時(shí)鐘,也沒了分時(shí),也不會(huì)有任何沖突問題。這就是硬件同步機(jī)制的主要思想。如果用鎖來描述的話,關(guān)中斷就是關(guān)鎖,開中斷就是開鎖,判斷鎖的狀態(tài)叫測試。為了防止多個(gè)進(jìn)程同時(shí)測試到鎖打開的情況,測試和關(guān)鎖必須是連續(xù)的。
??硬件同步的具體落實(shí)是通過硬件指令實(shí)現(xiàn)的,具體的有兩種:test-and-set、swap。(具體的不說了)
??信號(hào)量機(jī)制
??信號(hào)量其實(shí)也經(jīng)歷了一段發(fā)展的過程,基本順序可以分成:整型信號(hào)量、記錄型信號(hào)量、AND型信號(hào)量、信號(hào)量集,依次介紹下
??整型信號(hào)量:
??所謂整形信號(hào)量就是定義一個(gè)整型量表示資源的使用情況,只有兩個(gè)操作wait()和signal()能夠訪問。也對應(yīng)的稱wait()為P操作,signal()為V操作。
??兩個(gè)操作的實(shí)現(xiàn)如下(簡單描述):
??這個(gè)例子中S就是信號(hào)量,初始化為某一正整數(shù)n,代表資源的數(shù)目。當(dāng)資源的數(shù)目大于0時(shí)(有可用的資源)執(zhí)行資源自減,然后去做某一處理。當(dāng)資源為0時(shí)會(huì)一直卡在while處等待,直至某一進(jìn)程結(jié)束運(yùn)行后歸還資源再進(jìn)行分配。通過這種方式,我們就好像建立了一堵墻,拿到鑰匙(資源)才能夠訪問臨界區(qū)。
??想想這種方法有什么缺點(diǎn)呢?如果按照這個(gè)思路的話,拿不到資源的進(jìn)程會(huì)一直卡在while處,什么也不做,那這個(gè)時(shí)間片的各種資源就相當(dāng)于浪費(fèi)了。把這種現(xiàn)象稱為“忙等”。為了消除忙等,引入了記錄型信號(hào)量。
??記錄型信號(hào)量
??這種方法是解決了忙等問題。運(yùn)用的思想是通過改變進(jìn)程的狀態(tài)。之前說過阻塞狀態(tài)的進(jìn)程是不占據(jù)資源的。所有如果進(jìn)程執(zhí)行到指定位置但沒有資源可用,就改變進(jìn)程狀態(tài)為阻塞狀態(tài)。同時(shí)用鏈表這種結(jié)構(gòu)對所有阻塞進(jìn)程進(jìn)行保存。對于二者的代碼描述如下:
??之前說資源可以有很多個(gè),當(dāng)只有一個(gè)的時(shí)候。這時(shí)候的信號(hào)量叫做互斥信號(hào)量。
??使用記錄型信號(hào)量幫助我們解決了忙等問題,但再想一下,當(dāng)面臨多個(gè)信號(hào)量時(shí)wait()的順序是否會(huì)影響呢?答案是肯定的!看下面這個(gè):
??如果這個(gè)交錯(cuò)執(zhí)行的話,就發(fā)現(xiàn)死鎖了。引起問題的原因就是順序不對,那要是能一起執(zhí)行就好了,這就是AND型信號(hào)量!
??對于信號(hào)量集就是為了模型更一般化,在這里不進(jìn)行詳細(xì)討論了。平時(shí)用的感覺也少。
??對于信號(hào)量(PV操作)更重要的在應(yīng)用上,這篇文章主要是一些概念。后面會(huì)有一篇專門研究PV操作的幾個(gè)典型例題,去了解如何使用PV操作。
??進(jìn)程這部分到這里也就寫完了,但感覺還遠(yuǎn)沒有領(lǐng)悟到精髓,后面再繼續(xù)學(xué)習(xí)吧!
因作者水平有限,如果有錯(cuò)誤之處,請?jiān)谙路皆u論區(qū)指正,謝謝!
總結(jié)
- 上一篇: python2 http请求post、g
- 下一篇: 什么是HOOK功能?