進(jìn)程和線程基礎(chǔ)知識全家桶,30 張圖一套帶走
先來看看一則小故事
“哎喲,難道本文內(nèi)容是進(jìn)程和線程?”


正文
進(jìn)程

并發(fā)和并行有什么區(qū)別?

進(jìn)程與程序的關(guān)系的類比

進(jìn)程的狀態(tài)

運(yùn)行狀態(tài)(Runing):該時刻進(jìn)程占用 CPU; 就緒狀態(tài)(Ready):可運(yùn)行,但因為其他進(jìn)程正在運(yùn)行而暫停停止; 阻塞狀態(tài)(Blocked):該進(jìn)程正在等待某一事件發(fā)生(如等待輸入/輸出操作的完成)而暫時停止運(yùn)行,這時,即使給它CPU控制權(quán),它也無法運(yùn)行;
創(chuàng)建狀態(tài)(new):進(jìn)程正在被創(chuàng)建時的狀態(tài); 結(jié)束狀態(tài)(Exit):進(jìn)程正在從系統(tǒng)中消失時的狀態(tài);

NULL -> 創(chuàng)建狀態(tài):一個新進(jìn)程被創(chuàng)建時的第一個狀態(tài); 創(chuàng)建狀態(tài) -> 就緒狀態(tài):當(dāng)進(jìn)程被創(chuàng)建完成并初始化后,一切就緒準(zhǔn)備運(yùn)行時,變?yōu)榫途w狀態(tài),這個過程是很快的; 就緒態(tài) -> 運(yùn)行狀態(tài):處于就緒狀態(tài)的進(jìn)程被操作系統(tǒng)的進(jìn)程調(diào)度器選中后,就分配給 CPU 正式運(yùn)行該進(jìn)程; 運(yùn)行狀態(tài) -> 結(jié)束狀態(tài):當(dāng)進(jìn)程已經(jīng)運(yùn)行完成或出錯時,會被操作系統(tǒng)作結(jié)束狀態(tài)處理; 運(yùn)行狀態(tài) -> 就緒狀態(tài):處于運(yùn)行狀態(tài)的進(jìn)程在運(yùn)行過程中,由于分配給它的運(yùn)行時間片用完,操作系統(tǒng)會把該進(jìn)程變?yōu)榫途w態(tài),接著從就緒態(tài)選中另外一個進(jìn)程運(yùn)行; 運(yùn)行狀態(tài) -> 阻塞狀態(tài):當(dāng)進(jìn)程請求某個事件且必須等待時,例如請求 I/O 事件; 阻塞狀態(tài) -> 就緒狀態(tài):當(dāng)進(jìn)程要等待的事件完成時,它從阻塞狀態(tài)變到就緒狀態(tài);

阻塞掛起狀態(tài):進(jìn)程在外存(硬盤)并等待某個事件的出現(xiàn); 就緒掛起狀態(tài):進(jìn)程在外存(硬盤),但只要進(jìn)入內(nèi)存,即刻立刻運(yùn)行;

進(jìn)程的控制結(jié)構(gòu)

PCB 具體包含什么信息呢?
進(jìn)程標(biāo)識符:標(biāo)識各個進(jìn)程,每個進(jìn)程都有一個并且唯一的標(biāo)識符; 用戶標(biāo)識符:進(jìn)程歸屬的用戶,用戶標(biāo)識符主要為共享和保護(hù)服務(wù);
進(jìn)程當(dāng)前狀態(tài),如 new、ready、running、waiting 或 blocked 等; 進(jìn)程優(yōu)先級:進(jìn)程搶占 CPU 時的優(yōu)先級;
有關(guān)內(nèi)存地址空間或虛擬地址空間的信息,所打開文件的列表和所使用的 I/O 設(shè)備信息。
CPU 中各個寄存器的值,當(dāng)進(jìn)程被切換時,CPU 的狀態(tài)信息都會被保存在相應(yīng)的 PCB 中,以便進(jìn)程重新執(zhí)行時,能從斷點(diǎn)處繼續(xù)執(zhí)行。
每個 PCB 是如何組織的呢?
將所有處于就緒狀態(tài)的進(jìn)程鏈在一起,稱為就緒隊列; 把所有因等待某事件而處于等待狀態(tài)的進(jìn)程鏈在一起就組成各種阻塞隊列; 另外,對于運(yùn)行隊列在單核 CPU 系統(tǒng)中則只有一個運(yùn)行指針了,因為單核 CPU 在某個時間,只能運(yùn)行一個程序。

進(jìn)程的控制
為新進(jìn)程分配一個唯一的進(jìn)程標(biāo)識號,并申請一個空白的 PCB,PCB 是有限的,若申請失敗則創(chuàng)建失敗; 為進(jìn)程分配資源,此處如果資源不足,進(jìn)程就會進(jìn)入等待狀態(tài),以等待資源; 初始化 PCB; 如果進(jìn)程的調(diào)度隊列能夠接納新進(jìn)程,那就將進(jìn)程插入到就緒隊列,等待被調(diào)度運(yùn)行;
kill 掉)。查找需要終止的進(jìn)程的 PCB; 如果處于執(zhí)行狀態(tài),則立即終止該進(jìn)程的執(zhí)行,然后將 CPU 資源分配給其他進(jìn)程; 如果其還有子進(jìn)程,則應(yīng)將其所有子進(jìn)程終止; 將該進(jìn)程所擁有的全部資源都?xì)w還給父進(jìn)程或操作系統(tǒng); 將其從 PCB 所在隊列中刪除;
找到將要被阻塞進(jìn)程標(biāo)識號對應(yīng)的 PCB; 如果該進(jìn)程為運(yùn)行狀態(tài),則保護(hù)其現(xiàn)場,將其狀態(tài)轉(zhuǎn)為阻塞狀態(tài),停止運(yùn)行; 將該 PCB 插入的阻塞隊列中去;
在該事件的阻塞隊列中找到相應(yīng)進(jìn)程的 PCB; 將其從阻塞隊列中移出,并置其狀態(tài)為就緒狀態(tài); 把該 PCB 插入到就緒隊列中,等待調(diào)度程序調(diào)度;
進(jìn)程的上下文切換
在詳細(xì)說進(jìn)程上下文切換前,我們先來看看 CPU 上下文切換
進(jìn)程的上下文切換到底是切換什么呢?

發(fā)生進(jìn)程上下文切換有哪些場景?
為了保證所有進(jìn)程可以得到公平調(diào)度,CPU 時間被劃分為一段段的時間片,這些時間片再被輪流分配給各個進(jìn)程。這樣,當(dāng)某個進(jìn)程的時間片耗盡了,就會被系統(tǒng)掛起,切換到其它正在等待 CPU 的進(jìn)程運(yùn)行; 進(jìn)程在系統(tǒng)資源不足(比如內(nèi)存不足)時,要等到資源滿足后才可以運(yùn)行,這個時候進(jìn)程也會被掛起,并由系統(tǒng)調(diào)度其他進(jìn)程運(yùn)行; 當(dāng)進(jìn)程通過睡眠函數(shù) sleep 這樣的方法將自己主動掛起時,自然也會重新調(diào)度; 當(dāng)有優(yōu)先級更高的進(jìn)程運(yùn)行時,為了保證高優(yōu)先級進(jìn)程的運(yùn)行,當(dāng)前進(jìn)程會被掛起,由高優(yōu)先級進(jìn)程來運(yùn)行; 發(fā)生硬件中斷時,CPU 上的進(jìn)程會被中斷掛起,轉(zhuǎn)而執(zhí)行內(nèi)核中的中斷服務(wù)程序;
線程
為什么使用線程?
從視頻文件當(dāng)中讀取數(shù)據(jù); 對讀取的數(shù)據(jù)進(jìn)行解壓縮; 把解壓縮后的視頻數(shù)據(jù)播放出來;

播放出來的畫面和聲音會不連貫,因為當(dāng) CPU 能力不夠強(qiáng)的時候, Read?的時候可能進(jìn)程就等在這了,這樣就會導(dǎo)致等半天才進(jìn)行數(shù)據(jù)解壓和播放;各個函數(shù)之間不是并發(fā)執(zhí)行,影響資源的使用效率;

進(jìn)程之間如何通信,共享數(shù)據(jù)? 維護(hù)進(jìn)程的系統(tǒng)開銷較大,如創(chuàng)建進(jìn)程時,分配資源、建立 PCB;終止進(jìn)程時,回收資源、撤銷 PCB;進(jìn)程切換時,保存當(dāng)前進(jìn)程的狀態(tài)信息;
實(shí)體之間可以并發(fā)運(yùn)行; 實(shí)體之間共享相同的地址空間;
什么是線程?

線程的優(yōu)缺點(diǎn)?
一個進(jìn)程中可以同時存在多個線程; 各個線程之間可以并發(fā)執(zhí)行; 各個線程之間可以共享地址空間和文件等資源;
當(dāng)進(jìn)程中的一個線程奔潰時,會導(dǎo)致其所屬進(jìn)程的所有線程奔潰。
線程與進(jìn)程的比較
進(jìn)程是資源(包括內(nèi)存、打開的文件等)分配的單位,線程是 CPU 調(diào)度的單位; 進(jìn)程擁有一個完整的資源平臺,而線程只獨(dú)享必不可少的資源,如寄存器和棧; 線程同樣具有就緒、阻塞、執(zhí)行三種基本狀態(tài),同樣具有狀態(tài)之間的轉(zhuǎn)換關(guān)系; 線程能減少并發(fā)執(zhí)行的時間和空間開銷;
線程的創(chuàng)建時間比進(jìn)程快,因為進(jìn)程在創(chuàng)建的過程中,還需要資源管理信息,比如內(nèi)存管理信息、文件管理信息,而線程在創(chuàng)建的過程中,不會涉及這些資源管理信息,而是共享它們; 線程的終止時間比進(jìn)程快,因為線程釋放的資源相比進(jìn)程少很多; 同一個進(jìn)程內(nèi)的線程切換比進(jìn)程切換快,因為線程具有相同的地址空間(虛擬內(nèi)存共享),這意味著同一個進(jìn)程的線程都具有同一個頁表,那么在切換的時候不需要切換頁表。而對于進(jìn)程之間的切換,切換的時候要把頁表給切換掉,而頁表的切換過程開銷是比較大的; 由于同一進(jìn)程的各線程間共享內(nèi)存和文件資源,那么在線程之間數(shù)據(jù)傳遞的時候,就不需要經(jīng)過內(nèi)核了,這就使得線程之間的數(shù)據(jù)交互效率更高了;
線程的上下文切換
當(dāng)進(jìn)程只有一個線程時,可以認(rèn)為進(jìn)程就等于線程; 當(dāng)進(jìn)程擁有多個線程時,這些線程會共享相同的虛擬內(nèi)存和全局變量等資源,這些資源在上下文切換時是不需要修改的;
線程上下文切換的是什么?
當(dāng)兩個線程不是屬于同一個進(jìn)程,則切換的過程就跟進(jìn)程上下文切換一樣; 當(dāng)兩個線程是屬于同一個進(jìn)程,因為虛擬內(nèi)存是共享的,所以在切換時,虛擬內(nèi)存這些資源就保持不動,只需要切換線程的私有數(shù)據(jù)、寄存器等不共享的數(shù)據(jù);
線程的實(shí)現(xiàn)
用戶線程(User Thread):在用戶空間實(shí)現(xiàn)的線程,不是由內(nèi)核管理的線程,是由用戶態(tài)的線程庫來完成線程的管理; 內(nèi)核線程(Kernel Thread):在內(nèi)核中實(shí)現(xiàn)的線程,是由內(nèi)核管理的線程; 輕量級進(jìn)程(LightWeight Process):在內(nèi)核中來支持用戶線程;



用戶線程如何理解?存在什么優(yōu)勢和缺陷?

每個進(jìn)程都需要有它私有的線程控制塊(TCB)列表,用來跟蹤記錄它各個線程狀態(tài)信息(PC、棧指針、寄存器),TCB 由用戶級線程庫函數(shù)來維護(hù),可用于不支持線程技術(shù)的操作系統(tǒng); 用戶線程的切換也是由線程庫函數(shù)來完成的,無需用戶態(tài)與內(nèi)核態(tài)的切換,所以速度特別快;
由于操作系統(tǒng)不參與線程的調(diào)度,如果一個線程發(fā)起了系統(tǒng)調(diào)用而阻塞,那進(jìn)程所包含的用戶線程都不能執(zhí)行了。 當(dāng)一個線程開始運(yùn)行后,除非它主動地交出 CPU 的使用權(quán),否則它所在的進(jìn)程當(dāng)中的其他線程無法運(yùn)行,因為用戶態(tài)的線程沒法打斷當(dāng)前運(yùn)行中的線程,它沒有這個特權(quán),只有操作系統(tǒng)才有,但是用戶線程不是由操作系統(tǒng)管理的。 由于時間片分配給進(jìn)程,故與其他進(jìn)程比,在多線程執(zhí)行時,每個線程得到的時間片較少,執(zhí)行會比較慢;
那內(nèi)核線程如何理解?存在什么優(yōu)勢和缺陷?

在一個進(jìn)程當(dāng)中,如果某個內(nèi)核線程發(fā)起系統(tǒng)調(diào)用而被阻塞,并不會影響其他內(nèi)核線程的運(yùn)行; 分配給線程,多線程的進(jìn)程獲得更多的 CPU 運(yùn)行時間;
在支持內(nèi)核線程的操作系統(tǒng)中,由內(nèi)核來維護(hù)進(jìn)程和線程的上下問信息,如 PCB 和 TCB; 線程的創(chuàng)建、終止和切換都是通過系統(tǒng)調(diào)用的方式來進(jìn)行,因此對于系統(tǒng)來說,系統(tǒng)開銷比較大;
最后的輕量級進(jìn)程如何理解?
1 : 1,即一個 LWP 對應(yīng) 一個用戶線程;N : 1,即一個 LWP 對應(yīng)多個用戶線程;N : N,即多個 LMP 對應(yīng)多個用戶線程;

優(yōu)點(diǎn):實(shí)現(xiàn)并行,當(dāng)一個 LWP 阻塞,不會影響其他 LWP; 缺點(diǎn):每一個用戶線程,就產(chǎn)生一個內(nèi)核線程,創(chuàng)建線程的開銷較大。
優(yōu)點(diǎn):用戶線程要開幾個都沒問題,且上下文切換發(fā)生用戶空間,切換的效率較高; 缺點(diǎn):一個用戶線程如果阻塞了,則整個進(jìn)程都將會阻塞,另外在多核 CPU ?中,是沒辦法充分利用 CPU 的。
M:N 模型,該模型提供了兩級控制,首先多個用戶線程對應(yīng)到多個 LWP,LWP 再一一對應(yīng)到內(nèi)核線程,如上圖的進(jìn)程 3。優(yōu)點(diǎn):綜合了前兩種優(yōu)點(diǎn),大部分的線程上下文發(fā)生在用戶空間,且多個線程又可以充分利用多核 CPU 的資源。
1:1 模型和 M:N 模型。開發(fā)人員可以針對不同的應(yīng)用特點(diǎn)調(diào)節(jié)內(nèi)核線程的數(shù)目來達(dá)到物理并行性和邏輯并行性的最佳方案。調(diào)度
調(diào)度時機(jī)
從就緒態(tài) -> 運(yùn)行態(tài):當(dāng)進(jìn)程被創(chuàng)建時,會進(jìn)入到就緒隊列,操作系統(tǒng)會從就緒隊列選擇一個進(jìn)程運(yùn)行; 從運(yùn)行態(tài) -> 阻塞態(tài):當(dāng)進(jìn)程發(fā)生 I/O 事件而阻塞時,操作系統(tǒng)必須另外一個進(jìn)程運(yùn)行; 從運(yùn)行態(tài) -> 結(jié)束態(tài):當(dāng)進(jìn)程退出結(jié)束后,操作系統(tǒng)得從就緒隊列選擇另外一個進(jìn)程運(yùn)行;
,把調(diào)度算法分為兩類:
非搶占式調(diào)度算法挑選一個進(jìn)程,然后讓該進(jìn)程運(yùn)行直到被阻塞,或者直到該進(jìn)程退出,才會調(diào)用另外一個進(jìn)程,也就是說不會理時鐘中斷這個事情。 搶占式調(diào)度算法挑選一個進(jìn)程,然后讓該進(jìn)程只運(yùn)行某段時間,如果在該時段結(jié)束時,該進(jìn)程仍然在運(yùn)行時,則會把它掛起,接著調(diào)度程序從就緒隊列挑選另外一個進(jìn)程。這種搶占式調(diào)度處理,需要在時間間隔的末端發(fā)生時鐘中斷,以便把 CPU 控制返回給調(diào)度程序進(jìn)行調(diào)度,也就是常說的時間片機(jī)制。
調(diào)度原則

CPU 利用率:調(diào)度程序應(yīng)確保 CPU 是始終匆忙的狀態(tài),這可提高 CPU 的利用率; 系統(tǒng)吞吐量:吞吐量表示的是單位時間內(nèi) CPU 完成進(jìn)程的數(shù)量,長作業(yè)的進(jìn)程會占用較長的 CPU 資源,因此會降低吞吐量,相反,短作業(yè)的進(jìn)程會提升系統(tǒng)吞吐量; 周轉(zhuǎn)時間:周轉(zhuǎn)時間是進(jìn)程運(yùn)行和阻塞時間總和,一個進(jìn)程的周轉(zhuǎn)時間越小越好; 等待時間:這個等待時間不是阻塞狀態(tài)的時間,而是進(jìn)程處于就緒隊列的時間,等待的時間越長,用戶越不滿意; 響應(yīng)時間:用戶提交請求到系統(tǒng)第一次產(chǎn)生響應(yīng)所花費(fèi)的時間,在交互式系統(tǒng)中,響應(yīng)時間是衡量調(diào)度算法好壞的主要標(biāo)準(zhǔn)。
調(diào)度算法
01 先來先服務(wù)調(diào)度算法

02 最短作業(yè)優(yōu)先調(diào)度算法

03 高響應(yīng)比優(yōu)先調(diào)度算法

如果兩個進(jìn)程的「等待時間」相同時,「要求的服務(wù)時間」越短,「響應(yīng)比」就越高,這樣短作業(yè)的進(jìn)程容易被選中運(yùn)行; 如果兩個進(jìn)程「要求的服務(wù)時間」相同時,「等待時間」越長,「響應(yīng)比」就越高,這就兼顧到了長作業(yè)進(jìn)程,因為進(jìn)程的響應(yīng)比可以隨時間等待的增加而提高,當(dāng)其等待時間足夠長時,其響應(yīng)比便可以升到很高,從而獲得運(yùn)行的機(jī)會;
04 時間片輪轉(zhuǎn)調(diào)度算法
。

如果時間片用完,進(jìn)程還在運(yùn)行,那么將會把此進(jìn)程從 CPU 釋放出來,并把 CPU 分配另外一個進(jìn)程; 如果該進(jìn)程在時間片結(jié)束前阻塞或結(jié)束,則 CPU 立即進(jìn)行切換;
如果時間片設(shè)得太短會導(dǎo)致過多的進(jìn)程上下文切換,降低了 CPU 效率; 如果設(shè)得太長又可能引起對短作業(yè)進(jìn)程的響應(yīng)時間變長。將
20ms~50ms 通常是一個比較合理的折中值。05 最高優(yōu)先級調(diào)度算法
靜態(tài)優(yōu)先級:創(chuàng)建進(jìn)程時候,就已經(jīng)確定了優(yōu)先級了,然后整個運(yùn)行時間優(yōu)先級都不會變化; 動態(tài)優(yōu)先級:根據(jù)進(jìn)程的動態(tài)變化調(diào)整優(yōu)先級,比如如果進(jìn)程運(yùn)行時間增加,則降低其優(yōu)先級,如果進(jìn)程等待時間(就緒隊列的等待時間)增加,則升高其優(yōu)先級,也就是隨著時間的推移增加等待進(jìn)程的優(yōu)先級。
非搶占式:當(dāng)就緒隊列中出現(xiàn)優(yōu)先級高的進(jìn)程,運(yùn)行完當(dāng)前進(jìn)程,再選擇優(yōu)先級高的進(jìn)程。 搶占式:當(dāng)就緒隊列中出現(xiàn)優(yōu)先級高的進(jìn)程,當(dāng)前進(jìn)程掛起,調(diào)度優(yōu)先級高的進(jìn)程運(yùn)行。
06 多級反饋隊列調(diào)度算法
「多級」表示有多個隊列,每個隊列優(yōu)先級從高到低,同時優(yōu)先級越高時間片越短。 「反饋」表示如果有新的進(jìn)程加入優(yōu)先級高的隊列時,立刻停止當(dāng)前正在運(yùn)行的進(jìn)程,轉(zhuǎn)而去運(yùn)行優(yōu)先級高的隊列;

設(shè)置了多個隊列,賦予每個隊列不同的優(yōu)先級,每個隊列優(yōu)先級從高到低,同時優(yōu)先級越高時間片越短; 新的進(jìn)程會被放入到第一級隊列的末尾,按先來先服務(wù)的原則排隊等待被調(diào)度,如果在第一級隊列規(guī)定的時間片沒運(yùn)行完成,則將其轉(zhuǎn)入到第二級隊列的末尾,以此類推,直至完成; 當(dāng)較高優(yōu)先級的隊列為空,才調(diào)度較低優(yōu)先級的隊列中的進(jìn)程運(yùn)行。如果進(jìn)程運(yùn)行時,有新進(jìn)程進(jìn)入較高優(yōu)先級的隊列,則停止當(dāng)前運(yùn)行的進(jìn)程并將其移入到原隊列末尾,接著讓較高優(yōu)先級的進(jìn)程運(yùn)行;
看的迷迷糊糊?那我拿去銀行辦業(yè)務(wù)的例子,把上面的調(diào)度算法串起來,你還不懂,你錘我!






銀行設(shè)置了多個排隊(就緒)隊列,每個隊列都有不同的優(yōu)先級,各個隊列優(yōu)先級從高到低,同時每個隊列執(zhí)行時間片的長度也不同,優(yōu)先級越高的時間片越短。 新客戶(進(jìn)程)來了,先進(jìn)入第一級隊列的末尾,按先來先服務(wù)原則排隊等待被叫號(運(yùn)行)。如果時間片用完客戶的業(yè)務(wù)還沒辦理完成,則讓客戶進(jìn)入到下一級隊列的末尾,以此類推,直至客戶業(yè)務(wù)辦理完成。 當(dāng)?shù)谝患夑犃袥]人排隊時,就會叫號二級隊列的客戶。如果客戶辦理業(yè)務(wù)過程中,有新的客戶加入到較高優(yōu)先級的隊列,那么此時辦理中的客戶需要停止辦理,回到原隊列的末尾等待再次叫號,因為要把窗口讓給剛進(jìn)入較高優(yōu)先級隊列的客戶。
有道無術(shù),術(shù)可成;有術(shù)無道,止于術(shù)
歡迎大家關(guān)注Java之道公眾號
好文章,我在看??
評論
圖片
表情
