《Linux操作系統(tǒng)原理與應(yīng)用》課件第4章_第1頁(yè)
《Linux操作系統(tǒng)原理與應(yīng)用》課件第4章_第2頁(yè)
《Linux操作系統(tǒng)原理與應(yīng)用》課件第4章_第3頁(yè)
《Linux操作系統(tǒng)原理與應(yīng)用》課件第4章_第4頁(yè)
《Linux操作系統(tǒng)原理與應(yīng)用》課件第4章_第5頁(yè)
已閱讀5頁(yè),還剩167頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第4章進(jìn)程管理

4.1進(jìn)程4.2進(jìn)程的運(yùn)行模式4.3進(jìn)程控制4.4進(jìn)程調(diào)度4.5進(jìn)程的互斥與同步4.6進(jìn)程通信4.7線程習(xí)題

4.1進(jìn)程

進(jìn)程是現(xiàn)代操作系統(tǒng)的核心概念,它用來(lái)描述程序的執(zhí)行過(guò)程,是實(shí)現(xiàn)多任務(wù)操作系統(tǒng)的基礎(chǔ)。操作系統(tǒng)的其他所有內(nèi)容都是圍饒著進(jìn)程展開的。因此,正確地理解和認(rèn)識(shí)進(jìn)程是理解操作系統(tǒng)原理的基礎(chǔ)和關(guān)鍵。4.1.1程序的順序執(zhí)行與并發(fā)執(zhí)行

1.程序的順序執(zhí)行

如果程序的各操作步驟之間是依序執(zhí)行的,程序與程序之間是串行執(zhí)行的,這種執(zhí)行程序的方式就稱為順序執(zhí)行。順序執(zhí)行是單道程序系統(tǒng)中的程序的運(yùn)行方式。

程序的順序執(zhí)行具有如下特點(diǎn):

(1)順序性:CPU嚴(yán)格按照程序規(guī)定的順序執(zhí)行,僅當(dāng)一個(gè)操作結(jié)束后,下一個(gè)操作才能開始執(zhí)行。多個(gè)程序要運(yùn)行時(shí),僅當(dāng)一個(gè)程序全部執(zhí)行結(jié)束后另一個(gè)程序才能開始。

(2)封閉性:程序在封閉的環(huán)境中運(yùn)行,即程序運(yùn)行時(shí)獨(dú)占全部系統(tǒng)資源,只有程序本身才能改變程序的運(yùn)行環(huán)境。因而程序的執(zhí)行過(guò)程不受外界因素的影響,結(jié)果只取決于程序自身。

(3)可再現(xiàn)性:程序執(zhí)行的結(jié)果與運(yùn)行的時(shí)間和速度無(wú)關(guān),結(jié)果總是可再現(xiàn)的,即無(wú)論何時(shí)重復(fù)執(zhí)行該程序都會(huì)得到同樣的結(jié)果。

總的說(shuō)來(lái),這種執(zhí)行程序的方式簡(jiǎn)單,且便于調(diào)試。但由于順序程序在運(yùn)行時(shí)獨(dú)占全部系統(tǒng)資源,因而系統(tǒng)資源利用率很低。DOS程序就是采用順序方式執(zhí)行的。

2.程序的并發(fā)執(zhí)行

單道程序、封閉式運(yùn)行是早期操作系統(tǒng)的標(biāo)志,而多道程序并發(fā)運(yùn)行是現(xiàn)代操作系統(tǒng)的基本特征。由于同時(shí)有多個(gè)程序在系統(tǒng)中運(yùn)行,使系統(tǒng)資源得到充分的利用,系統(tǒng)效率大大提高。

程序的并發(fā)執(zhí)行是指若干個(gè)程序或程序段同時(shí)運(yùn)行。它們的執(zhí)行在時(shí)間上是重疊的,即同一程序或不同程序的程序段可以交叉執(zhí)行。程序的并發(fā)執(zhí)行有以下特點(diǎn):

(1)間斷性:并發(fā)程序之間因競(jìng)爭(zhēng)資源而相互制約,導(dǎo)致程序運(yùn)行過(guò)程的間斷。例如,在只有一個(gè)CPU的系統(tǒng)中,多個(gè)程序需要輪流占用CPU運(yùn)行,未獲得CPU使用權(quán)的程序就必須等待。

(2)沒(méi)有封閉性:當(dāng)多個(gè)程序共享系統(tǒng)資源時(shí),一個(gè)程序的運(yùn)行受其他程序的影響,其運(yùn)行過(guò)程和結(jié)果不完全由自身決定。例如,一個(gè)程序計(jì)劃在某一時(shí)刻執(zhí)行一個(gè)操作,但很可能在那個(gè)時(shí)刻到來(lái)時(shí)它沒(méi)有獲得CPU的使用權(quán),因而也就無(wú)法完成該操作。

(3)不可再現(xiàn)性:由于沒(méi)有了封閉性,并發(fā)程序的執(zhí)行結(jié)果與執(zhí)行的時(shí)機(jī)以及執(zhí)行的速度有關(guān),結(jié)果往往不可再現(xiàn)。

可以看出,并發(fā)執(zhí)行程序雖然可以提高系統(tǒng)的資源利用率和吞吐量,但程序的行為變得復(fù)雜和不確定。這使程序難以調(diào)試,若處理不當(dāng)還會(huì)帶來(lái)許多潛在問(wèn)題。

3.并發(fā)執(zhí)行的潛在問(wèn)題

程序在并發(fā)執(zhí)行時(shí)會(huì)導(dǎo)致執(zhí)行結(jié)果的不可再現(xiàn)性,這是多道程序系統(tǒng)必須解決的問(wèn)題。我們用下面的例子來(lái)說(shuō)明并發(fā)執(zhí)行過(guò)程對(duì)運(yùn)行結(jié)果的影響,從而了解產(chǎn)生問(wèn)題的原因。

設(shè)某停車場(chǎng)使用程序控制電子公告牌來(lái)顯示空閑車位數(shù)??臻e車位數(shù)用一個(gè)計(jì)數(shù)器C記錄。車輛入庫(kù)時(shí)執(zhí)行程序A,車輛出庫(kù)時(shí)執(zhí)行程序B,它們都要更新同一個(gè)計(jì)數(shù)器C。程序A和程序B的片段如圖4-1所示。圖4?1兩程序并發(fā)運(yùn)行,訪問(wèn)計(jì)數(shù)器C更新計(jì)數(shù)器C的操作對(duì)應(yīng)的機(jī)器語(yǔ)言有3個(gè)步驟:讀取內(nèi)存C單元的數(shù)據(jù)到一個(gè)寄存器中,修改寄存器的數(shù)值,然后再將其寫回C單元中。

由于車輛出入庫(kù)的時(shí)間是隨機(jī)的,程序A與程序B的運(yùn)行時(shí)間也就是不確定的。當(dāng)出入庫(kù)同時(shí)發(fā)生時(shí),將使兩程序在系統(tǒng)中并發(fā)運(yùn)行。它們各運(yùn)行一次后C計(jì)數(shù)器的值應(yīng)保持不變。但結(jié)果可能不是如此。如果兩個(gè)程序的運(yùn)行時(shí)序按圖4-2(a)所示的順序進(jìn)行,即一個(gè)程序?qū)進(jìn)行更新的操作是在另一個(gè)程序的更新操作全部完成之后才開始,則C被正確地更新了。如果兩個(gè)程序的運(yùn)行時(shí)序如圖4-2(b)所示穿插地進(jìn)行,即當(dāng)一個(gè)程序正在更新C,更新操作還未完成時(shí),CPU發(fā)生了切換,另一個(gè)程序被調(diào)度運(yùn)行,并且也對(duì)C進(jìn)行更新。在這種情況下會(huì)導(dǎo)致錯(cuò)誤的結(jié)果。

可以看出,導(dǎo)致C更新錯(cuò)誤的原因是兩個(gè)程序交叉地執(zhí)行了更新C的操作。概括地說(shuō),當(dāng)多個(gè)程序在訪問(wèn)共享資源時(shí)的操作是交叉執(zhí)行時(shí),則會(huì)發(fā)生對(duì)資源使用上的錯(cuò)誤。圖4?2并發(fā)程序的執(zhí)行時(shí)序影響執(zhí)行結(jié)果4.1.2進(jìn)程的概念

進(jìn)程的概念最早出現(xiàn)在20世紀(jì)60年代中期,此時(shí)操作系統(tǒng)進(jìn)入多道程序設(shè)計(jì)時(shí)代。多道程序并發(fā)顯著地提高了系統(tǒng)的效率,但同時(shí)也使程序的執(zhí)行過(guò)程變得復(fù)雜而不確定。為了更好地研究、描述和控制并發(fā)程序的執(zhí)行過(guò)程,操作系統(tǒng)引入了進(jìn)程的概念。進(jìn)程概念對(duì)于理解操作系統(tǒng)的并發(fā)性有著極為重要的意義。

1.進(jìn)程

進(jìn)程(process)是一個(gè)可并發(fā)執(zhí)行的程序在某數(shù)據(jù)集上的一次運(yùn)行。簡(jiǎn)單地說(shuō),進(jìn)程就是程序的一次運(yùn)行過(guò)程。

進(jìn)程與程序的概念既相互關(guān)聯(lián)又相互區(qū)別。程序是進(jìn)程的一個(gè)組成部分,是進(jìn)程的執(zhí)行文本,而進(jìn)程是程序的執(zhí)行過(guò)程。兩者的關(guān)系可以比喻為電影與膠片的關(guān)系:膠片是靜態(tài)的,是電影的放映素材。而電影是動(dòng)態(tài)的,一場(chǎng)電影就是膠片在放映機(jī)上的一次“運(yùn)行”。對(duì)進(jìn)程而言,程序是靜態(tài)的指令集合,可以永久存在;而進(jìn)程是個(gè)動(dòng)態(tài)的過(guò)程實(shí)體,動(dòng)態(tài)地產(chǎn)生、發(fā)展和消失。此外,進(jìn)程與程序之間也不是一一對(duì)應(yīng)的關(guān)系,表現(xiàn)在:

(1)一個(gè)進(jìn)程可以順序執(zhí)行多個(gè)程序,如同一場(chǎng)電影可以連續(xù)播放多部膠片一樣。

(2)一個(gè)程序可以對(duì)應(yīng)多個(gè)進(jìn)程,就像一本膠片可以放映多場(chǎng)電影一樣。程序的每次運(yùn)行就對(duì)應(yīng)了一個(gè)不同的進(jìn)程。更重要的是,一個(gè)程序還可以同時(shí)對(duì)應(yīng)多個(gè)進(jìn)程。比如系統(tǒng)中只有一個(gè)vi程序,但它可以被多個(gè)用戶同時(shí)執(zhí)行,編輯各自的文件。每個(gè)用戶的編輯過(guò)程都是一個(gè)不同的進(jìn)程。

2.進(jìn)程的特性

進(jìn)程與程序的不同主要體現(xiàn)在進(jìn)程有一些程序所沒(méi)有的特性。要真正理解進(jìn)程,首先應(yīng)了解它的基本性質(zhì)。進(jìn)程具有以下幾個(gè)基本特性:

(1)動(dòng)態(tài)性:進(jìn)程由“創(chuàng)建”而產(chǎn)生,由“撤銷”而消亡,因“調(diào)度”而運(yùn)行,因“等待”而停頓。進(jìn)程從創(chuàng)建到消失的全過(guò)程稱為進(jìn)程的生命周期。

(2)并發(fā)性:在同一時(shí)間段內(nèi)有多個(gè)進(jìn)程在系統(tǒng)中活動(dòng)。它們宏觀上是在并發(fā)運(yùn)行,而微觀上是在交替運(yùn)行。

(3)獨(dú)立性:進(jìn)程是可以獨(dú)立運(yùn)行的基本單位,是操作系統(tǒng)分配資源和調(diào)度管理的基本對(duì)象。因此,每個(gè)進(jìn)程都獨(dú)立地?fù)碛懈鞣N必要的資源,獨(dú)立地占有CPU并獨(dú)立地運(yùn)行。

(4)異步性:每個(gè)進(jìn)程都獨(dú)立地執(zhí)行,各自按照不可預(yù)知的速度向前推進(jìn)。進(jìn)程之間的協(xié)調(diào)運(yùn)行由操作系統(tǒng)負(fù)責(zé)。

3.進(jìn)程的基本狀態(tài)

在多道系統(tǒng)中,進(jìn)程的個(gè)數(shù)總是多于CPU的個(gè)數(shù),因此它們需要輪流地占用CPU。從宏觀上看,所有進(jìn)程同時(shí)都在向前推進(jìn),而在微觀上,這些進(jìn)程是在走走停停之間完成整個(gè)運(yùn)行過(guò)程的。為了刻畫一個(gè)進(jìn)程在各個(gè)時(shí)期的動(dòng)態(tài)行為特征,通常采用狀態(tài)圖模型。

進(jìn)程有3個(gè)基本的狀態(tài),即:

(1)就緒態(tài):進(jìn)程已經(jīng)分配到了除CPU之外的所有資源,這時(shí)的進(jìn)程狀態(tài)稱為就緒狀態(tài)。處于就緒態(tài)的進(jìn)程,一旦獲得CPU便可立即執(zhí)行。系統(tǒng)中通常會(huì)有多個(gè)進(jìn)程處于就緒態(tài),它們排成一個(gè)就緒隊(duì)列。

(2)運(yùn)行態(tài):進(jìn)程已經(jīng)獲得CPU,正在運(yùn)行,這時(shí)的進(jìn)程狀態(tài)稱為運(yùn)行態(tài)。在單CPU系統(tǒng)中,任何時(shí)刻只能有一個(gè)進(jìn)程處于運(yùn)行態(tài)。

(3)等待態(tài):進(jìn)程因某種資源不能滿足,或希望的某事件尚未發(fā)生而暫停執(zhí)行時(shí),則稱它處于等待態(tài)。系統(tǒng)中常常會(huì)有多個(gè)進(jìn)程處于等待態(tài),它們按等待的事件分類,排成多個(gè)等待隊(duì)列。

4.進(jìn)程狀態(tài)的轉(zhuǎn)換

進(jìn)程誕生之初是處于就緒狀態(tài),在其隨后的生存期間內(nèi)不斷地從一個(gè)狀態(tài)轉(zhuǎn)換到另一個(gè)狀態(tài),最后在運(yùn)行狀態(tài)結(jié)束。圖4-3所示是一個(gè)進(jìn)程的狀態(tài)轉(zhuǎn)換圖。

引起狀態(tài)轉(zhuǎn)換的原因如下:

運(yùn)行態(tài)→等待態(tài):正在執(zhí)行的進(jìn)程因?yàn)榈却呈录鵁o(wú)法執(zhí)行下去,比如,進(jìn)程申請(qǐng)某種資源,而該資源恰好被其他進(jìn)程占用,則該進(jìn)程將交出CPU,進(jìn)入等待狀態(tài)。圖4?3進(jìn)程的狀態(tài)轉(zhuǎn)換圖等待態(tài)→就緒態(tài):處于等待狀態(tài)的進(jìn)程,當(dāng)其所申請(qǐng)的資源得到滿足,則系統(tǒng)將資源分配給它,并將其狀態(tài)變?yōu)榫途w態(tài)。

運(yùn)行態(tài)→就緒態(tài):正在執(zhí)行的進(jìn)程的時(shí)間片用完了,或者有更高優(yōu)先級(jí)的進(jìn)程到來(lái),系統(tǒng)會(huì)暫停該進(jìn)程的運(yùn)行,使其進(jìn)入就緒態(tài),然后調(diào)度其他進(jìn)程運(yùn)行。

就緒態(tài)→運(yùn)行態(tài):處于就緒狀態(tài)的進(jìn)程,當(dāng)被進(jìn)程調(diào)度程序選中后,即進(jìn)入CPU運(yùn)行。此時(shí)該進(jìn)程的狀態(tài)變?yōu)檫\(yùn)行態(tài)。4.1.3進(jìn)程控制塊

進(jìn)程由程序、數(shù)據(jù)和進(jìn)程控制塊3部分組成,其中程序是進(jìn)程執(zhí)行的可執(zhí)行代碼,數(shù)據(jù)是進(jìn)程所處理的對(duì)象,進(jìn)程控制塊記錄進(jìn)程的所有信息。它們存在于內(nèi)存,其內(nèi)容會(huì)隨著執(zhí)行過(guò)程的進(jìn)展而不斷變化。在某個(gè)時(shí)刻的進(jìn)程的內(nèi)容被稱為進(jìn)程映像(processimage)。

系統(tǒng)中每個(gè)進(jìn)程都是唯一的,用一個(gè)進(jìn)程控制塊描述。即使兩個(gè)進(jìn)程執(zhí)行的是同一程序,處理同一數(shù)據(jù),它們的進(jìn)程控制塊也是不同的。因此可以說(shuō),進(jìn)程控制塊是進(jìn)程的

標(biāo)志。

1.進(jìn)程控制塊

進(jìn)程控制塊(ProcessControlBlock,PCB)是系統(tǒng)為管理進(jìn)程設(shè)置的一個(gè)數(shù)據(jù)結(jié)構(gòu),用于記錄進(jìn)程的相關(guān)信息。PCB是系統(tǒng)感知和控制進(jìn)程的一個(gè)數(shù)據(jù)實(shí)體。當(dāng)創(chuàng)建一個(gè)進(jìn)程時(shí),系統(tǒng)為它生成PCB;進(jìn)程完成后,撤銷它的PCB。因此,PCB是進(jìn)程的代表,PCB存在則進(jìn)程就存在,PCB消失則進(jìn)程也就結(jié)束了。在進(jìn)程的生存期中,系統(tǒng)通過(guò)PCB來(lái)了解進(jìn)程的活動(dòng)情況,對(duì)進(jìn)程實(shí)施控制和調(diào)度。因此,PCB是操作系統(tǒng)中的最重要數(shù)據(jù)結(jié)構(gòu)之一。

2.進(jìn)程控制塊的內(nèi)容

PCB記錄了有關(guān)進(jìn)程的系統(tǒng)所關(guān)心的所有信息,主要包括以下4方面的內(nèi)容:

1)進(jìn)程描述信息

進(jìn)程描述信息用于記錄一個(gè)進(jìn)程的特征和基本情況,通過(guò)這些信息可以識(shí)別該進(jìn)程,了解該進(jìn)程的歸屬信息,以及確定這個(gè)進(jìn)程與其他進(jìn)程之間的關(guān)系。

系統(tǒng)為每個(gè)進(jìn)程分配了一個(gè)唯一的整數(shù)作為進(jìn)程標(biāo)識(shí)號(hào)PID,通過(guò)這個(gè)PID來(lái)標(biāo)識(shí)這個(gè)進(jìn)程。操作系統(tǒng)、用戶以及其他進(jìn)程都是通過(guò)PID來(lái)識(shí)別進(jìn)程的。此外,還要描述進(jìn)程的家族關(guān)系,即父進(jìn)程(創(chuàng)建該進(jìn)程的進(jìn)程)和子進(jìn)程(該進(jìn)程創(chuàng)建的進(jìn)程)的信息。

2)進(jìn)程控制和調(diào)度信息

進(jìn)程是系統(tǒng)運(yùn)行調(diào)度的基本單位。進(jìn)程控制塊記錄了進(jìn)程的當(dāng)前狀態(tài)、調(diào)度信息、記時(shí)信息等。系統(tǒng)依據(jù)這些信息確定進(jìn)程的狀態(tài),實(shí)施進(jìn)程控制和調(diào)度。

3)資源信息

系統(tǒng)以進(jìn)程為單位分配資源,并將資源信息記錄在進(jìn)程的PCB中。資源包括該進(jìn)程使用的存儲(chǔ)器空間、打開的文件以及設(shè)備等。通過(guò)這些信息,進(jìn)程就可以得到運(yùn)行需要的相關(guān)程序段與數(shù)據(jù)段、使用文件和設(shè)備等資源。

4)現(xiàn)場(chǎng)信息

現(xiàn)場(chǎng)信息一般包括CPU的內(nèi)部寄存器和系統(tǒng)堆棧等,它們的值刻畫了進(jìn)程的運(yùn)行狀態(tài)。退出CPU的進(jìn)程必須保存好這些現(xiàn)場(chǎng)狀態(tài),以便在下次被調(diào)度時(shí)繼續(xù)運(yùn)行。當(dāng)一個(gè)進(jìn)程被重新調(diào)度運(yùn)行時(shí),要用PCB中的現(xiàn)場(chǎng)信息來(lái)恢復(fù)CPU的運(yùn)行現(xiàn)場(chǎng)?,F(xiàn)場(chǎng)一旦切換,下一個(gè)指令周期CPU將精確地接著上次運(yùn)行的斷點(diǎn)處繼續(xù)執(zhí)行下去。4.1.4進(jìn)程的組織

管理進(jìn)程就是管理進(jìn)程的PCB。一個(gè)系統(tǒng)中通??赡軗碛袛?shù)百乃至上千個(gè)進(jìn)程,為了有效地管理如此多的PCB,系統(tǒng)需要采用適當(dāng)?shù)姆绞綄⑺鼈兘M織在一起。所有的PCB都存放在內(nèi)存中,通常采用的組織結(jié)構(gòu)有數(shù)組、索引和鏈表3種方式。

數(shù)組方式是將所有的PCB順序存放在一個(gè)一維數(shù)組中。這種方式比較簡(jiǎn)單,但操作起來(lái)效率低,比如,要查找某個(gè)PCB時(shí)需要掃描全表。

索引方式是通過(guò)在PCB數(shù)組上設(shè)置索引表或散列表,以加快訪問(wèn)速度。鏈表方式是將PCB鏈接起來(lái),構(gòu)成鏈?zhǔn)疥?duì)列或鏈表。例如,所有就緒的PCB鏈成一個(gè)就緒隊(duì)列;所有等待的PCB按等待的事件鏈成多個(gè)等待隊(duì)列。這樣,在進(jìn)程調(diào)度時(shí)只要掃描就緒隊(duì)列即可,等待的事件發(fā)生時(shí)只要掃描相應(yīng)的等待隊(duì)列即可。當(dāng)進(jìn)程狀態(tài)發(fā)生轉(zhuǎn)換時(shí),鏈?zhǔn)浇Y(jié)構(gòu)允許方便地向隊(duì)列插入和刪除一個(gè)PCB。

實(shí)際的系統(tǒng)中通常會(huì)結(jié)合采用這些方法,以求達(dá)到最好的效率。4.1.5Linux系統(tǒng)中的進(jìn)程

在Linux系統(tǒng)中,進(jìn)程也稱為任務(wù)(task),兩者的概念是一致的。

1.?Linux進(jìn)程的狀態(tài)

Linux的進(jìn)程共有5種基本狀態(tài),包括運(yùn)行、就緒、睡眠(分為可中斷的與不可中斷的)、暫停和僵死。狀態(tài)轉(zhuǎn)換圖如圖4-4所示。圖4-4Linux系統(tǒng)的進(jìn)程狀態(tài)轉(zhuǎn)換圖

Linux將這些基本狀態(tài)歸結(jié)為4種并加以命名和定義,它們是:

(1)可執(zhí)行態(tài)(runnable):可執(zhí)行態(tài)實(shí)際包含了上述基本狀態(tài)中的運(yùn)行和就緒兩種狀態(tài)。處于可執(zhí)行態(tài)的進(jìn)程均已具備運(yùn)行條件。它們或正在運(yùn)行,或準(zhǔn)備運(yùn)行。

(2)睡眠態(tài)(sleeping):即等待態(tài)。進(jìn)程在等待某個(gè)事件或某個(gè)資源。睡眠態(tài)又細(xì)分為可中斷的(interruptible)和不可中斷的(uninterruptible)兩種。它們的區(qū)別在于,在睡眠過(guò)程中,不可中斷狀態(tài)的進(jìn)程會(huì)忽略信號(hào),而處于可中斷狀態(tài)的進(jìn)程如果收到信號(hào)會(huì)被喚醒而進(jìn)入可執(zhí)行狀態(tài),待處理完信號(hào)后再次進(jìn)入睡眠狀態(tài)。

(3)暫停態(tài)(stopped):處于暫停態(tài)的進(jìn)程一般都是由運(yùn)行態(tài)轉(zhuǎn)換而來(lái),等待某種特殊處理。比如調(diào)試跟蹤的程序,每執(zhí)行到一個(gè)斷點(diǎn),就轉(zhuǎn)入暫停態(tài),等待新的輸入信號(hào)。

(4)僵死態(tài)(zombie):進(jìn)程運(yùn)行結(jié)束或因某些原因被終止時(shí),它將釋放除PCB外的所有資源。這種占有PCB但已經(jīng)無(wú)法運(yùn)行的進(jìn)程就處于僵死狀態(tài)。

2.?Linux進(jìn)程的狀態(tài)轉(zhuǎn)換過(guò)程

Linux進(jìn)程的狀態(tài)轉(zhuǎn)換過(guò)程是:新創(chuàng)建的進(jìn)程處于可執(zhí)行的就緒態(tài),等待調(diào)度執(zhí)行。

處于可執(zhí)行態(tài)的進(jìn)程在就緒態(tài)和運(yùn)行態(tài)之間輪回。就緒態(tài)的進(jìn)程一旦被調(diào)度程序選中,就進(jìn)入運(yùn)行狀態(tài)。等時(shí)間片耗盡之后,退出CPU,轉(zhuǎn)入就緒狀態(tài)等待下一次的調(diào)度。處于此輪回的進(jìn)程在運(yùn)行與就緒之間不斷地高速切換,可謂瞬息萬(wàn)變。因此,對(duì)觀察者(系統(tǒng)與用戶)來(lái)說(shuō),將此輪回概括為一個(gè)相對(duì)穩(wěn)定的可執(zhí)行態(tài)才有意義。運(yùn)行態(tài)、睡眠態(tài)和就緒態(tài)形成一個(gè)回路。處于運(yùn)行態(tài)的進(jìn)程,有時(shí)需要等待某個(gè)事件或某種資源的發(fā)生,這時(shí)已無(wú)法占有CPU繼續(xù)工作,于是它就退出CPU,轉(zhuǎn)入睡眠狀態(tài)。當(dāng)所等待的事件發(fā)生后,進(jìn)程被喚醒,進(jìn)入就緒狀態(tài)。

運(yùn)行態(tài)、暫停態(tài)和就緒態(tài)也構(gòu)成一個(gè)回路。當(dāng)處于運(yùn)行態(tài)的進(jìn)程接收到暫停執(zhí)行信號(hào)時(shí),它就放棄CPU,進(jìn)入暫停態(tài)。當(dāng)暫停的進(jìn)程獲得恢復(fù)執(zhí)行信號(hào)時(shí),就轉(zhuǎn)入就緒態(tài)。

處于運(yùn)行態(tài)的進(jìn)程調(diào)用退出函數(shù)exit之后,進(jìn)入僵死態(tài)。當(dāng)父進(jìn)程對(duì)該進(jìn)程進(jìn)行相應(yīng)的處理后,撤銷其PCB。此時(shí),這個(gè)進(jìn)程就完成了它的使命,從僵死走向徹底消失。

3.?Linux的進(jìn)程控制塊

Linux系統(tǒng)的PCB用一個(gè)稱為task_struct的結(jié)構(gòu)體來(lái)描述。系統(tǒng)中每創(chuàng)建一個(gè)新的進(jìn)程,就給它分配一個(gè)task_struct結(jié)構(gòu),并填入進(jìn)程的控制信息。task_struct主要包括以下內(nèi)容:

(1)進(jìn)程標(biāo)識(shí)號(hào)(PID):PID是標(biāo)識(shí)該進(jìn)程的一個(gè)整數(shù)。系統(tǒng)通過(guò)這個(gè)標(biāo)識(shí)號(hào)來(lái)唯一地標(biāo)識(shí)一個(gè)進(jìn)程。

(2)用戶標(biāo)識(shí)(UID)和組標(biāo)識(shí)(GID):描述進(jìn)程的歸屬關(guān)系,即進(jìn)程的屬主和屬組的標(biāo)識(shí)號(hào)。系統(tǒng)通過(guò)這兩個(gè)標(biāo)識(shí)號(hào)判斷進(jìn)程對(duì)文件和設(shè)備的訪問(wèn)權(quán)限。

(3)鏈接信息:用指針的方式記錄進(jìn)程的父進(jìn)程、兄弟進(jìn)程以及子進(jìn)程的位置(即PCB的地址)。系統(tǒng)通過(guò)鏈接信息確定進(jìn)程的家族關(guān)系以及其在整個(gè)進(jìn)程鏈中的位置。

(4)狀態(tài):進(jìn)程當(dāng)前的狀態(tài)。

(5)調(diào)度信息:與系統(tǒng)調(diào)度相關(guān)的信息,包括優(yōu)先級(jí)、時(shí)間片和調(diào)度策略。

(6)記時(shí)信息:包括時(shí)間和定時(shí)器。時(shí)間記錄進(jìn)程建立的時(shí)間以及進(jìn)程占用CPU的時(shí)間統(tǒng)計(jì),是進(jìn)程調(diào)度、統(tǒng)計(jì)和監(jiān)控的依據(jù)。定時(shí)器用于設(shè)定一個(gè)時(shí)間。時(shí)間到時(shí),系統(tǒng)會(huì)發(fā)定時(shí)信號(hào)通知進(jìn)程。

(7)通信信息:記錄有關(guān)進(jìn)程間信號(hào)量通信及信號(hào)通信的信息。

(8)退出碼:記錄進(jìn)程運(yùn)行結(jié)束后的退出狀態(tài),供父進(jìn)程查詢用。

(9)文件系統(tǒng)信息:包括根目錄、當(dāng)前目錄、打開的文件以及文件創(chuàng)建掩碼等信息。

(10)內(nèi)存信息:記錄進(jìn)程的代碼映像和堆棧的地址、長(zhǎng)度等信息。

(11)進(jìn)程現(xiàn)場(chǎng)信息:保存進(jìn)程放棄CPU時(shí)所有CPU寄存器及堆棧的當(dāng)前值。

4.查看進(jìn)程的信息

在Linux系統(tǒng)中,要查看進(jìn)程的信息可使用ps(processstatus)命令。該命令可查看記錄在進(jìn)程PCB中的幾乎所有信息。

ps命令

【功能】查看進(jìn)程的信息。

【格式】ps[選項(xiàng)]

【選項(xiàng)】

-e 顯示所有進(jìn)程。

-f 以全格式顯示。

-r 只顯示正在運(yùn)行的進(jìn)程。

-o 以用戶定義的格式顯示。

a 顯示所有終端上的所有進(jìn)程。

u 以面向用戶的格式顯示。

x 顯示所有不控制終端的進(jìn)程。

【說(shuō)明】

(1)默認(rèn)只顯示在本終端上運(yùn)行的進(jìn)程,除非指定了-e、a、x等選項(xiàng)。

(2)沒(méi)有指定顯示格式時(shí),采用以下缺省格式,分4列顯示:

PIDTTYTIMECMD各字段的含義是:

PID 進(jìn)程標(biāo)識(shí)號(hào)。

TTY 進(jìn)程對(duì)應(yīng)的終端,?表示該進(jìn)程不占用終端。

TIME 進(jìn)程累計(jì)使用的CPU時(shí)間。

CMD 進(jìn)程執(zhí)行的命令名。

(1)指定-f選項(xiàng)時(shí),以全格式,分8列顯示:

UIDPIDPPIDCSTIMETTYTIMECMD

各字段的含義是:

UID 進(jìn)程屬主的用戶名。

PPID 父進(jìn)程的標(biāo)識(shí)號(hào)。

C 進(jìn)程最近使用的CPU時(shí)間。

STIME 進(jìn)程開始時(shí)間。

其余同上。

(2)指定u選項(xiàng)時(shí),以用戶格式,分11列顯示:

USERPID%CPU%MEMVSZRSSTTYSTATSTARTTIMECOMMAND

各字段的含義是:

USER 同UID。

%CPU 進(jìn)程占用CPU的時(shí)間與進(jìn)程總運(yùn)行時(shí)間之比。

%MEM 進(jìn)程占用的內(nèi)存與總內(nèi)存之比。

VSZ 進(jìn)程虛擬內(nèi)存的大小,以KB為單位。

RSS 占用實(shí)際內(nèi)存的大小,以KB為單位。

STAT 進(jìn)程當(dāng)前狀態(tài),用字母表示。含義:

R 執(zhí)行態(tài);

S 睡眠態(tài);

D 不可中斷睡眠態(tài);

T 暫停態(tài);

Z 僵尸態(tài)。

START 同STIME。

COMMAND 同CMD。

其余同上。

例4.1ps命令用法示例:

$ps #以缺省格式顯示本終端上的進(jìn)程的信息

PIDTTYTIMECMD

9805pts/000:00:00bash

9835pts/000:00:00ps

$ps-ef #以全格式顯示當(dāng)前系統(tǒng)中所有進(jìn)程的信息

UIDPIDPPIDCSTIMETTYTIMECMD

root10011:26?00:00:03/sbin/init

root20011:26?00:00:00[kthreadd]

root32011:26?00:00:00[migration/0]

root42011:26?00:00:51[ksoftirqd/0]

$psaux #以用戶格式顯示當(dāng)前系統(tǒng)中所有進(jìn)程的信息

USERPID%CPU%MEMVSZRSSTTYSTATSTARTTIMECOMMAND

root

1

0.0

0.11948

816

?

S11:260:03/sbin/init

root

2

0.0

0.0 ?0?

0

?

S11:260:00[kthreadd]

cherry98050.00.26184

1524pts/0S

22:310:00bash

cherry98760.00.15980940pts/0R

22:360:00psaux

$

5.Linux進(jìn)程的組織

Linux系統(tǒng)采用了多種方式來(lái)組織PCB,主要有以下幾種。

1)進(jìn)程鏈表

系統(tǒng)將所有的PCB鏈成一個(gè)雙向循環(huán)鏈表,進(jìn)程通過(guò)PCB中的list_head字段鏈入進(jìn)程鏈表。遍歷該鏈表即可順序地找到每個(gè)進(jìn)程。

在許多情況下,內(nèi)核需要根據(jù)進(jìn)程的PID查找進(jìn)程。順序掃描鏈表并逐個(gè)檢查PCB中的PID是相當(dāng)?shù)托У?。為了加速查找,?nèi)核還設(shè)置了幾個(gè)進(jìn)程散列表,將PID直接映射到PCB。

2)進(jìn)程樹鏈表

Linux系統(tǒng)中,進(jìn)程之間存在著父子關(guān)系。除了init進(jìn)程外,每個(gè)進(jìn)程都有一個(gè)父進(jìn)程,即創(chuàng)建了此進(jìn)程的進(jìn)程。一個(gè)進(jìn)程可以創(chuàng)建0至多個(gè)進(jìn)程,稱為它的子進(jìn)程。具有相同父進(jìn)程的進(jìn)程稱為兄弟進(jìn)程。這樣,系統(tǒng)中的所有進(jìn)程形成了一棵進(jìn)程樹,每個(gè)進(jìn)程都是樹中的一個(gè)節(jié)點(diǎn),樹的根是init進(jìn)程,它是所有進(jìn)程的祖先進(jìn)程。

在PCB中設(shè)置有父進(jìn)程指針parent、子進(jìn)程指針children和兄弟進(jìn)程指針sibling,它們構(gòu)造出了進(jìn)程樹的結(jié)構(gòu)。進(jìn)程通過(guò)這些指針可以直接找到它的家族成員。

3)可執(zhí)行隊(duì)列

為了方便進(jìn)程的調(diào)度,系統(tǒng)把所有處于可執(zhí)行狀態(tài)的PCB組織成一個(gè)可執(zhí)行隊(duì)列,處于可執(zhí)行狀態(tài)的進(jìn)程通過(guò)PCB中的run_list字段鏈入隊(duì)列??蓤?zhí)行隊(duì)列中設(shè)置了一個(gè)curr指針,它指向隊(duì)列中正在使用CPU的進(jìn)程,用來(lái)區(qū)別就緒態(tài)和運(yùn)行態(tài)的進(jìn)程。在進(jìn)程切換時(shí),進(jìn)程調(diào)度程序從可執(zhí)行隊(duì)列中選擇一個(gè)讓其運(yùn)行,并將curr指針指向它。

4)等待隊(duì)列

進(jìn)程因不同的原因而睡眠,例如,等待磁盤操作的數(shù)據(jù)、等待某系統(tǒng)資源可用或等待固定的時(shí)間間隔。系統(tǒng)將睡眠的進(jìn)程分類管理,每類對(duì)應(yīng)一個(gè)特定的事件,用一個(gè)等待隊(duì)列鏈接。等待隊(duì)列是一個(gè)雙向循環(huán)鏈表,鏈表的節(jié)點(diǎn)中包含了指向進(jìn)程PCB的指針。當(dāng)某一事件發(fā)生時(shí),內(nèi)核會(huì)喚醒相應(yīng)的等待隊(duì)列中滿足等待條件的進(jìn)程,將喚醒的進(jìn)程從隊(duì)列中刪除,加入到可執(zhí)行隊(duì)列中。

4.2進(jìn)程的運(yùn)行模式

進(jìn)程的運(yùn)行緊密依賴于操作系統(tǒng)的內(nèi)核。因此,理解進(jìn)程的運(yùn)行機(jī)制需要首先認(rèn)識(shí)內(nèi)核,了解內(nèi)核的運(yùn)行方式,進(jìn)而了解進(jìn)程在核心態(tài)與用戶態(tài)下的不同執(zhí)行模式。

4.2.1操作系統(tǒng)內(nèi)核

一個(gè)完整的操作系統(tǒng)由一個(gè)內(nèi)核和一些系統(tǒng)服務(wù)程序構(gòu)成。內(nèi)核(kernel)是操作系統(tǒng)的核心,它負(fù)責(zé)最基本的資源管理和控制工作,為進(jìn)程提供良好的運(yùn)行環(huán)境。

圖4-5是Linux系統(tǒng)的層次體系結(jié)構(gòu)。系統(tǒng)分為3層:最底層是系統(tǒng)硬件;硬件層之上是核心層,它是運(yùn)行程序和管理基本硬件的核心程序;用戶層由系統(tǒng)的核外程序和用戶程序組成,它們都是以用戶進(jìn)程的方式運(yùn)行在核心之上。圖4-5Linux系統(tǒng)的體系結(jié)構(gòu)內(nèi)核在系統(tǒng)引導(dǎo)時(shí)載入并常駐內(nèi)存,形成對(duì)硬件的第一層包裝。啟動(dòng)了內(nèi)核的系統(tǒng)具備了執(zhí)行進(jìn)程的所有條件,使進(jìn)程可以被正確地創(chuàng)建、運(yùn)行、控制和撤銷。為此,內(nèi)核應(yīng)具備支撐進(jìn)程運(yùn)行的所有功能,包括對(duì)進(jìn)程本身的控制及對(duì)進(jìn)程要使用的資源的管理。

Linux系統(tǒng)的內(nèi)核主要由以下成分構(gòu)成:

(1)進(jìn)程控制子系統(tǒng),負(fù)責(zé)支持、管理和控制進(jìn)程的運(yùn)行,包括以下模塊:

●進(jìn)程調(diào)度模塊,負(fù)責(zé)調(diào)度進(jìn)程的運(yùn)行。

●進(jìn)程通信模塊,實(shí)現(xiàn)進(jìn)程間的本地通信。

●內(nèi)存管理模塊,管理進(jìn)程的地址空間。

(2)文件子系統(tǒng),為進(jìn)程提供I/O環(huán)境,包括以下模塊和成分:

●文件系統(tǒng)模塊,管理文件和設(shè)備。

●網(wǎng)絡(luò)接口模塊,實(shí)現(xiàn)進(jìn)程間的網(wǎng)絡(luò)通信。

●設(shè)備驅(qū)動(dòng)程序,驅(qū)動(dòng)和控制設(shè)備的運(yùn)行。

(1)系統(tǒng)調(diào)用接口,提供進(jìn)程與內(nèi)核的接口,進(jìn)程通過(guò)此接口調(diào)用內(nèi)核的功能。

(2)硬件控制接口,是內(nèi)核與硬件的接口,負(fù)責(zé)控制硬件并響應(yīng)和處理中斷事件。4.2.2中斷與系統(tǒng)調(diào)用

由圖可以看出,內(nèi)核與外界的接口是來(lái)自用戶層的系統(tǒng)調(diào)用和來(lái)自硬件層的中斷,而系統(tǒng)調(diào)用本身也是一種特殊的中斷。因此可以說(shuō)內(nèi)核是中斷驅(qū)動(dòng)的,它的主要作用就是提供系統(tǒng)調(diào)用和中斷的處理。因此,了解內(nèi)核的運(yùn)行機(jī)制需要先了解中斷和系統(tǒng)調(diào)用的概念。

1.中斷

在早期的計(jì)算機(jī)系統(tǒng)中,CPU與各種設(shè)備是串行工作的。當(dāng)需要設(shè)備傳輸數(shù)據(jù)時(shí),CPU向設(shè)備發(fā)出指令,啟動(dòng)設(shè)備執(zhí)行數(shù)據(jù)傳輸操作。然后CPU不斷地測(cè)試設(shè)備的狀態(tài),直到它完成操作。在設(shè)備工作期間,CPU是處于原地踏步的循環(huán)中,這對(duì)CPU資源是極大的浪費(fèi)。

中斷技術(shù)的出現(xiàn)完全改變了計(jì)算機(jī)系統(tǒng)的操作模式。在現(xiàn)代系統(tǒng)中,CPU與各種設(shè)備是并發(fā)工作的。在中斷方式下,CPU啟動(dòng)設(shè)備操作后,它不是空閑等待,而是繼續(xù)執(zhí)行程序。當(dāng)設(shè)備完成I/O操作后,向CPU發(fā)出一種特定的中斷信號(hào),打斷CPU的運(yùn)行。CPU響應(yīng)中斷后暫停正在執(zhí)行的程序,轉(zhuǎn)去執(zhí)行專門的中斷處理程序,然后再返回原來(lái)的程序繼續(xù)執(zhí)行。這個(gè)過(guò)程就是中斷。中斷的概念是因?qū)崿F(xiàn)CPU與設(shè)備并行操作而引入的。然而,這個(gè)概念后來(lái)被大大地?cái)U(kuò)大了?,F(xiàn)在,系統(tǒng)中所有異步發(fā)生的事件都是通過(guò)中斷機(jī)制來(lái)處理的,包括I/O設(shè)備中斷、系統(tǒng)時(shí)鐘中斷、硬件故障中斷、軟件異常中斷等。這些中斷分為硬件中斷和軟件中斷(也稱為異常)兩大類。每個(gè)中斷都對(duì)應(yīng)一個(gè)中斷處理程序。中斷發(fā)生后,CPU通過(guò)中斷處理入口轉(zhuǎn)入相應(yīng)的處理程序來(lái)處理中斷事件。

關(guān)于中斷技術(shù)的更多介紹見7.2.1小節(jié)。

2.系統(tǒng)調(diào)用

系統(tǒng)調(diào)用是系統(tǒng)內(nèi)核提供的一組特殊的函數(shù),用戶進(jìn)程通過(guò)系統(tǒng)調(diào)用來(lái)訪問(wèn)系統(tǒng)資源。與普通函數(shù)的不同之處在于,普通函數(shù)是由用戶或函數(shù)庫(kù)提供的程序代碼,它們的運(yùn)行會(huì)受到系統(tǒng)的限制,不能訪問(wèn)系統(tǒng)資源。系統(tǒng)調(diào)用是內(nèi)核中的程序代碼,它們具有訪問(wèn)系統(tǒng)資源的特權(quán)。當(dāng)用戶進(jìn)程需要執(zhí)行涉及系統(tǒng)資源的操作時(shí),需要通過(guò)系統(tǒng)調(diào)用,讓內(nèi)核來(lái)完成。

系統(tǒng)調(diào)用是借助中斷機(jī)制實(shí)現(xiàn)的,它是軟中斷的一種,稱為“系統(tǒng)調(diào)用”中斷。當(dāng)進(jìn)程執(zhí)行到一個(gè)系統(tǒng)調(diào)用時(shí),就會(huì)產(chǎn)生一個(gè)系統(tǒng)調(diào)用中斷。CPU將響應(yīng)此中斷,轉(zhuǎn)入系統(tǒng)調(diào)用入口程序,然后調(diào)用內(nèi)核中相應(yīng)的系統(tǒng)調(diào)用處理函數(shù),執(zhí)行該系統(tǒng)調(diào)用對(duì)應(yīng)的功能。

關(guān)于系統(tǒng)調(diào)用的更多介紹見8.4節(jié)。4.2.3進(jìn)程的運(yùn)行模式

1.?CPU的執(zhí)行模式

CPU的基本功能就是執(zhí)行指令。通常,CPU指令集中的指令可以劃分為兩類:特權(quán)指令和非特權(quán)指令。特權(quán)指令是指具有特殊權(quán)限的指令,可以訪問(wèn)系統(tǒng)中所有寄存器和內(nèi)存單元,修改系統(tǒng)的關(guān)鍵設(shè)置。比如清理內(nèi)存、設(shè)置時(shí)鐘、執(zhí)行I/O操作等都是由特權(quán)指令完成的。而非特權(quán)指令是那些用于一般性的運(yùn)算和處理的指令。這些指令只能訪問(wèn)用戶程序自己的內(nèi)存地址空間。特權(quán)指令的權(quán)限高,如果使用不當(dāng)則可能會(huì)破壞系統(tǒng)或其他用戶的數(shù)據(jù),甚至導(dǎo)致系統(tǒng)崩潰。為了安全起見,這類指令只允許操作系統(tǒng)的內(nèi)核程序使用,而普通的應(yīng)用程序只能使用那些沒(méi)有危險(xiǎn)的非特權(quán)指令。實(shí)現(xiàn)這種限制的方法是在CPU中設(shè)置一個(gè)代表運(yùn)行模式的狀態(tài)字,修改這個(gè)狀態(tài)字就可以切換CPU的運(yùn)行模式。

386以上的CPU支持4種不同特權(quán)級(jí)別的運(yùn)行模式,Linux系統(tǒng)只用到了其中兩個(gè),即稱為核心態(tài)的最高特權(quán)級(jí)模式(ring0)和稱為用戶態(tài)的最低特權(quán)級(jí)模式(ring3)。在核心態(tài)下,CPU能不受限制地執(zhí)行所有指令,從而表現(xiàn)出最高的特權(quán)。而在用戶態(tài)下,CPU只能執(zhí)行一般指令,不能執(zhí)行特權(quán)指令,因而也就沒(méi)有特權(quán)。內(nèi)核的程序運(yùn)行在核心態(tài)下,而用戶程序則只能運(yùn)行在用戶態(tài)下。從用戶態(tài)轉(zhuǎn)換為核心態(tài)的唯一途徑是中斷(包括系統(tǒng)調(diào)用)。一旦CPU響應(yīng)了中斷,則將CPU的狀態(tài)切換到核心態(tài),待中斷處理結(jié)束返回時(shí),再將CPU狀態(tài)切回到用戶態(tài)。

2.進(jìn)程的運(yùn)行模式

進(jìn)程在其運(yùn)行期間常常被中斷或系統(tǒng)調(diào)用打斷,因此CPU也經(jīng)常地在用戶態(tài)與核心態(tài)之間切換。在進(jìn)行通常的計(jì)算和處理時(shí),進(jìn)程運(yùn)行在用戶態(tài);執(zhí)行系統(tǒng)調(diào)用或中斷處理程序時(shí)進(jìn)入核心態(tài),執(zhí)行內(nèi)核代碼。調(diào)用返回后,回到用戶態(tài)繼續(xù)運(yùn)行。圖4-6描述了用戶進(jìn)程的運(yùn)行模式切換。圖4-6用戶進(jìn)程的運(yùn)行模式切換在A期間,進(jìn)程運(yùn)行在用戶態(tài),執(zhí)行的是用戶程序代碼。運(yùn)行到某一時(shí)刻時(shí)發(fā)生了中斷,進(jìn)程隨即“陷入”核心態(tài)運(yùn)行。在B期間,CPU運(yùn)行在核心態(tài),執(zhí)行的是內(nèi)核程序代碼。此時(shí)有兩種情況:如果進(jìn)程是被中斷打斷的,則B期間執(zhí)行的是中斷處理程序,它是隨機(jī)插入的,與進(jìn)程本身無(wú)關(guān);如果進(jìn)程是因調(diào)用了系統(tǒng)調(diào)用而陷入內(nèi)核空間的,則B執(zhí)行的是內(nèi)核的系統(tǒng)調(diào)用程序代碼,它是作為進(jìn)程的一個(gè)執(zhí)行環(huán)節(jié),由內(nèi)核代理用戶進(jìn)程繼續(xù)執(zhí)行的。在中斷或系統(tǒng)調(diào)用返回后的C期間中,進(jìn)程在用戶態(tài)繼續(xù)運(yùn)行。

4.3進(jìn)程控制

進(jìn)程控制是指對(duì)進(jìn)程的生命周期進(jìn)行有效的管理,實(shí)現(xiàn)進(jìn)程的創(chuàng)建、撤銷以及進(jìn)程各狀態(tài)之間的轉(zhuǎn)換等控制功能。進(jìn)程控制的目標(biāo)是使多個(gè)進(jìn)程能夠平穩(wěn)高效地并發(fā)執(zhí)行,充分共享系統(tǒng)資源。4.3.1進(jìn)程控制的功能

進(jìn)程控制的功能是控制進(jìn)程在整個(gè)生命周期中各種狀態(tài)之間的轉(zhuǎn)換(不包括就緒態(tài)與運(yùn)行態(tài)之間的轉(zhuǎn)換,它們是由進(jìn)程調(diào)度來(lái)實(shí)現(xiàn)的)。為此,內(nèi)核提供了幾個(gè)原子性的操作函數(shù),稱為原語(yǔ)(primitive)。原語(yǔ)與普通函數(shù)的區(qū)別是它的各個(gè)指令的執(zhí)行是不可分割的,要么全部完成,要么一個(gè)也不做,因而可以看做是一條廣義的指令。用于進(jìn)程控制的原語(yǔ)主要有創(chuàng)建、終止、阻塞和喚醒等。

1)創(chuàng)建進(jìn)程

創(chuàng)建原語(yǔ)的主要任務(wù)是根據(jù)創(chuàng)建者提供的有關(guān)參數(shù)(包括進(jìn)程名、進(jìn)程優(yōu)先級(jí)、進(jìn)程代碼起始地址、資源清單等信息),建立進(jìn)程的PCB。具體的操作過(guò)程是:先申請(qǐng)一個(gè)空閑的PCB結(jié)構(gòu),調(diào)用資源分配程序?yàn)樗峙渌璧馁Y源,將有關(guān)信息填入PCB,狀態(tài)置為就緒態(tài),然后把它插入就緒(可執(zhí)行)隊(duì)列中。

2)撤銷進(jìn)程

撤銷原語(yǔ)用于在一個(gè)進(jìn)程運(yùn)行終止時(shí),撤銷這個(gè)進(jìn)程并釋放進(jìn)程占用的資源。撤銷的操作過(guò)程是:找到要被撤銷的進(jìn)程的PCB,將它從所在隊(duì)列中摘出,釋放進(jìn)程所占用的資源,最后銷去進(jìn)程的PCB。

3)阻塞進(jìn)程

阻塞原語(yǔ)用于完成從運(yùn)行態(tài)到等待態(tài)的轉(zhuǎn)換工作。當(dāng)正在運(yùn)行的進(jìn)程需要等待某一事件而無(wú)法執(zhí)行下去時(shí),它就調(diào)用阻塞原語(yǔ)把自己轉(zhuǎn)入等待狀態(tài)。阻塞原語(yǔ)具體的操作過(guò)程是:首先中斷CPU的執(zhí)行,把CPU的當(dāng)前狀態(tài)保存在PCB的現(xiàn)場(chǎng)信息中;然后把被阻塞的進(jìn)程置為等待狀態(tài),插入到相應(yīng)的等待隊(duì)列中;最后調(diào)用進(jìn)程調(diào)度程序,從就緒(可執(zhí)行)隊(duì)列中選擇一個(gè)進(jìn)程投入運(yùn)行。

4)喚醒進(jìn)程

喚醒原語(yǔ)用于完成等待態(tài)到就緒態(tài)的轉(zhuǎn)換工作。當(dāng)處于等待狀態(tài)的進(jìn)程所等待的事件出現(xiàn)時(shí),內(nèi)核會(huì)調(diào)用喚醒原語(yǔ)喚醒被阻塞的進(jìn)程。操作過(guò)程是:在等待隊(duì)列中找到該進(jìn)程,置進(jìn)程的當(dāng)前狀態(tài)為就緒態(tài),然后將它從等待隊(duì)列中撤出并插入到就緒(可執(zhí)行)隊(duì)列中。4.3.2Linux系統(tǒng)的進(jìn)程控制

在Linux系統(tǒng)中,進(jìn)程控制的功能是由內(nèi)核的進(jìn)程控制子系統(tǒng)實(shí)現(xiàn)的,并以系統(tǒng)調(diào)用的形式提供給用戶進(jìn)程或其他系統(tǒng)進(jìn)程使用。

1.進(jìn)程的創(chuàng)建與映像更換

系統(tǒng)啟動(dòng)時(shí)執(zhí)行初始化程序,啟動(dòng)進(jìn)程號(hào)為1的init進(jìn)程運(yùn)行。系統(tǒng)中所有的其他進(jìn)程都是由init進(jìn)程衍生而來(lái)的。除init進(jìn)程外,每個(gè)進(jìn)程都是由另一個(gè)進(jìn)程創(chuàng)建的。新創(chuàng)建的進(jìn)程稱為子進(jìn)程,創(chuàng)建子進(jìn)程的進(jìn)程稱為父進(jìn)程。

Unix/Linux系統(tǒng)建立新進(jìn)程的方式與眾不同。它不是一步構(gòu)造出新的進(jìn)程,而是采用先復(fù)制再變身的兩個(gè)步驟,即先按照父進(jìn)程創(chuàng)建一個(gè)子進(jìn)程,然后再更換進(jìn)程映像開始執(zhí)行。

1)創(chuàng)建進(jìn)程

創(chuàng)建一個(gè)進(jìn)程的系統(tǒng)調(diào)用是fork()。創(chuàng)建進(jìn)程采用的方法是克隆,即用父進(jìn)程復(fù)制一個(gè)子進(jìn)程。做法是:先獲得一個(gè)空閑的PCB,為子進(jìn)程分配一個(gè)PID,然后將父進(jìn)程的PCB中的代碼及資源復(fù)制給子進(jìn)程的PCB,狀態(tài)置為可執(zhí)行態(tài)。建好PCB后將其鏈接入進(jìn)程鏈表和可執(zhí)行隊(duì)列中。此后,子進(jìn)程與父進(jìn)程并發(fā)執(zhí)行。父子進(jìn)程執(zhí)行的是同一個(gè)代碼,使用的是同樣的資源。它與父進(jìn)程的區(qū)別僅僅在于PID(進(jìn)程號(hào))、PPID(父進(jìn)程號(hào))和與子進(jìn)程運(yùn)行相關(guān)的屬性(如狀態(tài)、累計(jì)運(yùn)行時(shí)間等),而這些是不能從父進(jìn)程那里繼承來(lái)的。

fork()系統(tǒng)調(diào)用

【功能】創(chuàng)建一個(gè)新的子進(jìn)程。

【調(diào)用格式】intfork();

【返回值】

0 向子進(jìn)程返回的返回值,總為0

>0 向父進(jìn)程返回的返回值,它是子進(jìn)程的PID。

-1 創(chuàng)建失敗。

【說(shuō)明】若fork()調(diào)用成功,則它向父進(jìn)程返回子進(jìn)程的PID,并向新建的子進(jìn)程返回0。

圖4-7描述了fork()系統(tǒng)調(diào)用的執(zhí)行結(jié)果。圖4-7fork系統(tǒng)調(diào)用的執(zhí)行結(jié)果從圖4-7中可以看出,當(dāng)一個(gè)進(jìn)程成功執(zhí)行了fork()后,從該調(diào)用點(diǎn)之后分裂成了兩個(gè)進(jìn)程:一個(gè)是父進(jìn)程,從fork()后的代碼處繼續(xù)運(yùn)行;另一個(gè)是新創(chuàng)建的子進(jìn)程,從fork()后的代碼處開始運(yùn)行。由fork()產(chǎn)生的進(jìn)程分裂在結(jié)構(gòu)上很像一把叉子,故得名fork()。

與一般函數(shù)不同,fork()是“一次調(diào)用,兩次返回”,因?yàn)檎{(diào)用成功后,已經(jīng)是兩個(gè)進(jìn)程了。由于子進(jìn)程是從父進(jìn)程那里復(fù)制的代碼,因此父子進(jìn)程執(zhí)行的是同一個(gè)程序,它們?cè)趫?zhí)行時(shí)的區(qū)別只在于得到的返回值不同。父進(jìn)程得到的返回值是一個(gè)大于0的數(shù),它是子進(jìn)程的PID;子進(jìn)程得到的返回值為0。若程序中不考慮fork()的返回值,則父子進(jìn)程的行為就完全一樣了。但創(chuàng)建一個(gè)子進(jìn)程的目的是想讓它做另一件事。所以,通常的做法是:在fork()調(diào)用后,通過(guò)判斷fork()的返回值,分別為父進(jìn)程和子進(jìn)程設(shè)計(jì)不同的執(zhí)行分支。這樣,父子進(jìn)程執(zhí)行的雖是同一個(gè)代碼,執(zhí)行路線卻分道揚(yáng)鑣。圖4-8描述了用fork()創(chuàng)建子進(jìn)程的常用流程。圖4-8用fork創(chuàng)建子進(jìn)程例4.2

一個(gè)簡(jiǎn)單的fork_test程序:

#include<stdio.h>

main()

{intrid;

rid=fork();

if(rid<0){printf(“forkerror!”);return;}

if(rid>0)//父進(jìn)程分支

printf(“Iamparent,myridis%d,myPIDis%d\n”,rid,getpid());

else//子進(jìn)程分支

printf(“Iamchild,myridis%d,myPIDis%d\n”,rid,getpid());

}注:程序中的getpid()是一個(gè)系統(tǒng)調(diào)用,它返回本進(jìn)程的進(jìn)程標(biāo)識(shí)號(hào)PID。

fork_test程序運(yùn)行時(shí),父子進(jìn)程將會(huì)輸出不同的信息,如父進(jìn)程的輸出可能是“Iamparent,myridis8229,myPIDis8228”;子進(jìn)程的輸出可能是“Iamchild,myridis0,myPIDis8229”。由于兩進(jìn)程是并發(fā)的,它們輸出信息的先后次序不確定,有可能父先子后,也可能相反。

2)更換進(jìn)程映像

進(jìn)程映像是指進(jìn)程所執(zhí)行的程序代碼及數(shù)據(jù)。fork()是將父進(jìn)程的執(zhí)行映像拷貝給子進(jìn)程,因而子進(jìn)程實(shí)際上是父進(jìn)程的克隆體。但通常用戶需要的是創(chuàng)建一個(gè)新的進(jìn)程,它執(zhí)行的是一個(gè)不同的程序。Linux系統(tǒng)的做法是,先用fork()克隆一個(gè)子進(jìn)程,然后在子進(jìn)程中調(diào)用exec(),使其脫胎換骨,變換為一個(gè)全新的進(jìn)程。

exec()系統(tǒng)調(diào)用的功能是根據(jù)參數(shù)指定的文件名找到程序文件,把它裝入內(nèi)存,覆蓋原來(lái)進(jìn)程的映像,從而形成一個(gè)不同于父進(jìn)程的全新的子進(jìn)程。除了進(jìn)程映像被更換外,新子進(jìn)程的PID及其他PCB屬性均保持不變,實(shí)際上是一個(gè)新的進(jìn)程“借殼”原來(lái)的子進(jìn)程開始運(yùn)行。

exec()系統(tǒng)調(diào)用

【功能】改變進(jìn)程的映像,使其執(zhí)行另外的程序。

【調(diào)用格式】exec()是一系列系統(tǒng)調(diào)用,共有6種調(diào)用格式,其中execve()是真正的系統(tǒng)調(diào)用,其余是對(duì)其包裝后的C庫(kù)函數(shù)。

intexecve(char*path,char*argv[],char*envp[]);

intexecl(char*path,char*arg0,char*arg1,...char*argn,0);

intexecle(char*path,char*arg0,char*arg1,...char*argn,0,char*exvp[]);

【參數(shù)說(shuō)明】path為要執(zhí)行的文件的路徑名,argv[]為運(yùn)行參數(shù)數(shù)組,envp[]為運(yùn)行環(huán)境數(shù)組。arg0為程序的名稱,arg1~argn為程序的運(yùn)行參數(shù),0表示參數(shù)結(jié)束。例如:

execl(“/bin/echo”,“echo”,“hello!”,0);

execle(“/bin/ls”,“l(fā)s”,“-l”,“/bin”,0,NULL);

前者表示更換進(jìn)程映像為/bin/echo文件,執(zhí)行的命令行是“echohello!”。后者表示更換進(jìn)程映像為/bin/ls文件,執(zhí)行的命令行是“l(fā)s-l/bin”。

【返回值】調(diào)用成功后,不返回,調(diào)用失敗后,返回

-1。與一般的函數(shù)不同,exec()是“一次調(diào)用,零次返回”,因?yàn)檎{(diào)用成功后,進(jìn)程的映像已經(jīng)被替換,無(wú)處可以返回了。圖4-9描述了用exec()系統(tǒng)調(diào)用更換進(jìn)程映像的流程。子進(jìn)程開始運(yùn)行后,立即調(diào)用exec(),變身成功后即開始執(zhí)行新的程序了。圖4-9用exec更換子進(jìn)程的映像

例4.3

一個(gè)簡(jiǎn)單的fork-exec_test程序:

#include<stdio.h>

main()

{intrid;

rid=fork();

if(rid>0)printf(“Iamparent\n”);

else{printf(“Iamchild,I’llchangetoecho!\n”);

execl(“/bin/echo”,“echo”,“hello!”,0);//更換為echo

}

}

Fork()返回后,父子進(jìn)程分別執(zhí)行各自的分支,父進(jìn)程輸出信息“Iamparent”。子進(jìn)程輸出信息“Iamchild,I’llchangetoecho!”,然后調(diào)用exec(),變換為echo程序。echo隨即開始執(zhí)行并輸出字符串“hello!”。

2.進(jìn)程的終止與等待

1)進(jìn)程的終止與退出狀態(tài)

導(dǎo)致一個(gè)進(jìn)程終止運(yùn)行的方式有兩種:一是程序中使用退出語(yǔ)句主動(dòng)終止運(yùn)行,我們稱其為正常終止;另一種是被某個(gè)信號(hào)殺死(例如,在進(jìn)程運(yùn)行時(shí)按Ctrl+c鍵終止其運(yùn)行),稱為非正常終止。關(guān)于信號(hào)的介紹見0節(jié)。

用C語(yǔ)言編程時(shí),可以通過(guò)以下4種方式主動(dòng)退出:

(1)調(diào)用exit(status)函數(shù)來(lái)結(jié)束程序;

(2)在main()函數(shù)中用returnstatus語(yǔ)句結(jié)束;

(3)在main()函數(shù)中用return語(yǔ)句結(jié)束;

(4)?main()函數(shù)結(jié)束。以上4種情況都會(huì)使進(jìn)程正常終止,前3種為顯式地終止程序的運(yùn)行,后1種為隱式地終止。正常終止的進(jìn)程可以返回給系統(tǒng)一個(gè)退出狀態(tài),即前2種語(yǔ)句中的status。通常的約定是:0表示正常狀態(tài);非0表示異常狀態(tài),不同取值表示異常的具體原因。例如對(duì)一個(gè)計(jì)算程序,可以約定退出狀態(tài)為0表示計(jì)算成功,為1表示運(yùn)算數(shù)有錯(cuò),為2表示運(yùn)算符有錯(cuò),等等。如果程序結(jié)束時(shí)沒(méi)有指定退出狀態(tài)(如后兩種退出),則它的退出狀態(tài)是不確定的。

設(shè)置退出狀態(tài)的作用是通知父進(jìn)程有關(guān)此次運(yùn)行的狀況,以便父進(jìn)程做相應(yīng)的處理。因此,顯式地結(jié)束程序并返回退出狀態(tài)是一個(gè)好的Unix/Linux編程習(xí)慣,這樣的程序可以將自己的運(yùn)行狀況告之系統(tǒng),因而能很好地與系統(tǒng)和其他程序合作。

2)終止進(jìn)程

進(jìn)程無(wú)論以哪種方式結(jié)束,都會(huì)調(diào)用一個(gè)exit()系統(tǒng)調(diào)用,通過(guò)這個(gè)系統(tǒng)調(diào)用終止自己的運(yùn)行,并及時(shí)通知父進(jìn)程回收本進(jìn)程。exit()系統(tǒng)調(diào)用完成以下操作:釋放進(jìn)程除PCB外的幾乎所有資源;向PCB寫入進(jìn)程退出狀態(tài)和一些統(tǒng)計(jì)信息;置進(jìn)程狀態(tài)為“僵死態(tài)”;向父進(jìn)程發(fā)送“子進(jìn)程終止(SIGCHLD)”信號(hào);調(diào)用進(jìn)程調(diào)度程序切換CPU的運(yùn)行進(jìn)程。至此,子進(jìn)程已變?yōu)椤敖┦M(jìn)程”,它不再具備任何執(zhí)行條件,只是PCB還在。保留PCB的目的是為了保存有關(guān)該進(jìn)程運(yùn)行情況的重要的信息,比如這個(gè)進(jìn)程的退出狀態(tài)、運(yùn)行時(shí)間的統(tǒng)計(jì)、收到信號(hào)的數(shù)目等。子進(jìn)程的最后回收工作由父進(jìn)程負(fù)責(zé)。父進(jìn)程收集子進(jìn)程的信息后將其PCB撤銷。如果某一個(gè)進(jìn)程由于某種原因先于子進(jìn)程終止,由它創(chuàng)建的子進(jìn)程就成為孤兒進(jìn)程。當(dāng)系統(tǒng)中出現(xiàn)孤兒進(jìn)程時(shí),init進(jìn)程將會(huì)發(fā)現(xiàn)并收養(yǎng)它,成為它的父進(jìn)程。由于init進(jìn)程不會(huì)退出,所以所有的進(jìn)程都會(huì)被收養(yǎng)。最后,在系統(tǒng)關(guān)機(jī)之前,init進(jìn)程要負(fù)責(zé)結(jié)束所有的進(jìn)程。

exit()系統(tǒng)調(diào)用

【功能】使進(jìn)程主動(dòng)終止。

【調(diào)用格式】voidexit(intstatus);

【參數(shù)說(shuō)明】status是要傳遞給父進(jìn)程的一個(gè)整數(shù),用于向父進(jìn)程通報(bào)進(jìn)程運(yùn)行的結(jié)果狀態(tài)。status的含義通常是:0表示正常終止;非0表示運(yùn)行有錯(cuò),異常終止。

3)等待與收集進(jìn)程

在并發(fā)執(zhí)行的環(huán)境中,父子進(jìn)程的運(yùn)行速度是無(wú)法確定的。但在許多情況下,我們希望父子進(jìn)程的進(jìn)展能夠有某種同步關(guān)系。比如,父進(jìn)程需要等待子進(jìn)程的運(yùn)行結(jié)果才能繼續(xù)執(zhí)行下一步計(jì)算,或父進(jìn)程要負(fù)責(zé)子進(jìn)程的回收工作,它必須在子進(jìn)程結(jié)束后才能退出。這時(shí)就需要通過(guò)wait()系統(tǒng)調(diào)用來(lái)阻塞父進(jìn)程,等待子進(jìn)程結(jié)束。

當(dāng)父進(jìn)程調(diào)用wait()時(shí),自己立即被阻塞,由wait()檢查是否有僵尸子進(jìn)程。如果找到就收集它的信息,然后撤掉它的PCB;否則就阻塞下去,等待子進(jìn)程發(fā)來(lái)終止信號(hào)。父進(jìn)程被信號(hào)喚醒后,執(zhí)行wait(),處理子進(jìn)程的回收工作。經(jīng)wait()收集后,子進(jìn)程才真正的消失。

wait()系統(tǒng)調(diào)用

【功能】阻塞進(jìn)程直到子進(jìn)程結(jié)束;收集子進(jìn)程。

【調(diào)用格式】intwait(int*statloc);

【參數(shù)說(shuō)明】*statloc保存了子進(jìn)程的一些狀態(tài)。如果是正常退出,則其末字節(jié)為0,第2字節(jié)為退出狀態(tài);如果是非正常退出(即被某個(gè)信號(hào)所終止),則其末字節(jié)不為0,末字節(jié)的低7位為導(dǎo)致進(jìn)程終止的信號(hào)的信號(hào)值。若不關(guān)心子進(jìn)程是如何終止的,可以用NULL作參數(shù),即wait(NULL)。

【返回值】

>0 子進(jìn)程的PID。

-1 調(diào)用失敗。

0 其他。

圖4-10描述了用wait()系統(tǒng)調(diào)用等待子進(jìn)程的流程。圖4-10用wait實(shí)現(xiàn)進(jìn)程的等待

例4.4

一個(gè)簡(jiǎn)單的wait-exit_test程序:

#include<stdio.h>

#include<stdlib.h>

main()

{intrid,cid,status;

rid=fork();

if(rid<0){printf(“forkerror!”);exit(1);}

if(rid==0){printf(“Iamachild.Iwillsleepawhile.\n”);

sleep(10); //睡眠10秒

exit(0);

}

cid=wait(&status);

printf(“IcatchedachildwithPIDof%d.\n”,cid);

if((status&0377)==0) //末字節(jié)為0

printf(“Itexitednormallywithstatusof%d.\n,status>>8);

elseprintf(“Itisterminatedbysignal%d.\n,status&0177);

exit(0);

}

此例的執(zhí)行過(guò)程是:父進(jìn)程在創(chuàng)建子進(jìn)程失敗時(shí)會(huì)用exit(1)退出。成功創(chuàng)建子進(jìn)程后,父進(jìn)程調(diào)用wait()阻塞自己;子進(jìn)程運(yùn)行,先輸出信息,睡眠10秒后用exit(0)退出向父進(jìn)程發(fā)信號(hào),告之自己已結(jié)束。父進(jìn)程被喚醒后,從wait()返回,根據(jù)獲得的子進(jìn)程的PID和退出狀態(tài)判斷子進(jìn)程的運(yùn)行情況并輸出相應(yīng)的信息,然后用exit(0)退出。

3.進(jìn)程的阻塞與喚醒

運(yùn)行中的進(jìn)程,若需要等待一個(gè)特定事件的發(fā)生而不能繼續(xù)運(yùn)行下去時(shí),則主動(dòng)放棄CPU。等待的事件可能是一段時(shí)間、從文件中讀出的數(shù)據(jù)、來(lái)自鍵盤的輸入、某個(gè)資源被釋放或是某個(gè)硬件產(chǎn)生的事件等。進(jìn)程通過(guò)調(diào)用內(nèi)核函數(shù)來(lái)阻塞自己,將自己加入到一個(gè)等待隊(duì)列中。阻塞操作的步驟是:建立一個(gè)等待隊(duì)列的節(jié)點(diǎn),填入本進(jìn)程的信息,將它鏈入指定的等待隊(duì)列中;將進(jìn)程的狀態(tài)置為睡眠態(tài);調(diào)用進(jìn)程調(diào)度函數(shù)選擇其他進(jìn)程運(yùn)行,并將本進(jìn)程從可執(zhí)行隊(duì)列中刪除。當(dāng)?shù)却氖录l(fā)生時(shí),引發(fā)事件的相關(guān)程序會(huì)調(diào)用內(nèi)核函數(shù)來(lái)喚醒等待隊(duì)列中的滿足等待條件的進(jìn)程。例如,當(dāng)磁盤數(shù)據(jù)到來(lái)后,文件系統(tǒng)要負(fù)責(zé)喚醒等待這批文件數(shù)據(jù)的進(jìn)程。喚醒操作的處理是:將進(jìn)程的狀態(tài)改變?yōu)榭蓤?zhí)行態(tài)并加到可執(zhí)行隊(duì)列中。如果此進(jìn)程的優(yōu)先級(jí)高于當(dāng)前正在運(yùn)行的進(jìn)程的優(yōu)先級(jí),則會(huì)觸發(fā)進(jìn)程調(diào)度函數(shù)重新進(jìn)行進(jìn)程調(diào)度。當(dāng)該進(jìn)程被調(diào)度執(zhí)行時(shí),它調(diào)用內(nèi)核函數(shù)把自己從等待隊(duì)列中刪除。

另外,信號(hào)也可以喚醒處于可中斷睡眠態(tài)的進(jìn)程。被信號(hào)喚醒為偽喚醒,即喚醒不是因?yàn)榈却氖录l(fā)生。被信號(hào)偽喚醒的進(jìn)程在處理完信號(hào)后通常會(huì)再次睡眠。4.3.3Shell命令的執(zhí)行過(guò)程

Shell程序的功能就是執(zhí)行Shell命令,執(zhí)行命令的主要方式是創(chuàng)建一個(gè)子進(jìn)程,讓這個(gè)子進(jìn)程來(lái)執(zhí)行命令的映像文件。因此,Shell進(jìn)程是所有在其下執(zhí)行的命令的父進(jìn)程。圖4-11所示是Shell執(zhí)行命令的大致過(guò)程,從中可以看到一個(gè)進(jìn)程從誕生到消失的整個(gè)過(guò)程。

Shell進(jìn)程初始化完成后,在屏幕上顯示命令提示符,等待命令行輸入。接收到一個(gè)命令行后,Shell對(duì)其進(jìn)行解析,確定要執(zhí)行的命令及其選項(xiàng)和參數(shù),以及命令的執(zhí)行方式,然后創(chuàng)建一個(gè)子Shell進(jìn)程。圖4-11Shell命令的執(zhí)行過(guò)程子進(jìn)程誕生后立即更換進(jìn)程映像為要執(zhí)行的命令的映像文件,運(yùn)行該命令直至結(jié)束。如果命令行后面沒(méi)有帶后臺(tái)運(yùn)行符“&”,則子進(jìn)程在前臺(tái)開始運(yùn)行。此時(shí),Shell阻塞自己,等待命令執(zhí)行結(jié)束。如果命令行后面帶有“&”符,則子進(jìn)程在后臺(tái)開始運(yùn)行,同時(shí)Shell也繼續(xù)執(zhí)行下去。它立即顯示命令提示符,接受下一個(gè)命令。命令子進(jìn)程執(zhí)行結(jié)束后,向父進(jìn)程Shell進(jìn)程發(fā)送信號(hào),由Shell對(duì)子進(jìn)程進(jìn)行回收處理。

4.4進(jìn)程調(diào)度

在多任務(wù)系統(tǒng)中,進(jìn)程調(diào)度是CPU管理的一項(xiàng)核心工作。根據(jù)調(diào)度模式的不同,多任務(wù)系統(tǒng)有兩種類型,即非搶占式和搶占式。非搶占模式是由正在運(yùn)行的進(jìn)程自己主動(dòng)放棄CPU,這是早期多任務(wù)系統(tǒng)的調(diào)度模式?,F(xiàn)代操作系統(tǒng)大多采用搶占式模式,即由調(diào)度程序決定什么時(shí)候停止一個(gè)進(jìn)程的運(yùn)行,切換其他進(jìn)程運(yùn)行。對(duì)于搶占式多任務(wù)系統(tǒng)來(lái)說(shuō),進(jìn)程調(diào)度是系統(tǒng)設(shè)計(jì)中最為關(guān)鍵的一個(gè)環(huán)節(jié)。4.4.1進(jìn)程調(diào)度的基本原理

1.進(jìn)程調(diào)度的功能

進(jìn)程調(diào)度的功能是按照一定的策略把CPU分配給就緒進(jìn)程,使它們輪流地使用CPU運(yùn)行。進(jìn)程調(diào)度實(shí)現(xiàn)了進(jìn)程就緒態(tài)與運(yùn)行態(tài)之間的轉(zhuǎn)換。調(diào)度工作包括:

(1)當(dāng)正運(yùn)行的進(jìn)程因某種原因放棄CPU時(shí),為該進(jìn)程保留現(xiàn)場(chǎng)信息。

(2)按一定的調(diào)度算法,從就緒進(jìn)程中選一個(gè)進(jìn)程,把CPU分配給它。

(3)為被選中的進(jìn)程恢復(fù)現(xiàn)場(chǎng),使其運(yùn)行。

2.進(jìn)程調(diào)度算法

進(jìn)程調(diào)度算法是系統(tǒng)效率的關(guān)鍵,它確定了系統(tǒng)對(duì)資源,特別是對(duì)CPU資源的分配策略,因而直接決定著系統(tǒng)最本質(zhì)的性能指標(biāo),如響應(yīng)速度、吞吐量等。進(jìn)程調(diào)度算法的目標(biāo)首先是要充分發(fā)揮CPU的處理能力,滿足進(jìn)程對(duì)CPU的需求。此外還要盡量做到公平對(duì)待每個(gè)進(jìn)程,使它們都能得到運(yùn)行機(jī)會(huì)。

常用的調(diào)度算法有:

(1)先進(jìn)先出法:按照進(jìn)程在就緒隊(duì)列中的先后次序來(lái)調(diào)度。這是最簡(jiǎn)單的調(diào)度法,但缺點(diǎn)是對(duì)一些緊迫任務(wù)的響應(yīng)時(shí)間過(guò)長(zhǎng)。

(2)短進(jìn)程優(yōu)先法:優(yōu)先調(diào)度短進(jìn)程運(yùn)行,以提高系統(tǒng)的吞吐量,但對(duì)長(zhǎng)進(jìn)程不利。

(3)時(shí)間片輪轉(zhuǎn)法:進(jìn)程按規(guī)定的時(shí)間片輪流使用CPU。這種方法可滿足分時(shí)系統(tǒng)對(duì)用戶響應(yīng)時(shí)間的要求,有很好的公平性。時(shí)間片長(zhǎng)度的選擇應(yīng)適當(dāng),過(guò)短會(huì)引起頻繁的進(jìn)程調(diào)度,過(guò)長(zhǎng)則對(duì)用戶的響應(yīng)較慢。

(4)優(yōu)先級(jí)調(diào)度法:為每個(gè)進(jìn)程設(shè)置優(yōu)先級(jí),調(diào)度時(shí)優(yōu)先選擇優(yōu)先級(jí)高的進(jìn)程運(yùn)行,使緊迫的任務(wù)可以優(yōu)先得到處理。更為細(xì)致的調(diào)度法又將優(yōu)先級(jí)分為靜態(tài)優(yōu)先級(jí)和動(dòng)態(tài)優(yōu)先級(jí)。靜態(tài)優(yōu)先級(jí)是預(yù)先指定的,動(dòng)態(tài)優(yōu)先級(jí)則隨進(jìn)程運(yùn)行時(shí)間的長(zhǎng)短而降低或升高。兩種優(yōu)先級(jí)組合調(diào)度,既可以保證對(duì)高優(yōu)先級(jí)進(jìn)程的響應(yīng),也不致過(guò)度忽略低優(yōu)先級(jí)的進(jìn)程。

實(shí)際應(yīng)用中,經(jīng)常是多種策略結(jié)合使用。如時(shí)間片輪轉(zhuǎn)法中也可適當(dāng)考慮優(yōu)先級(jí)因素,對(duì)于緊急的進(jìn)程可以分配一個(gè)長(zhǎng)一些的時(shí)間片,或連續(xù)運(yùn)行多個(gè)時(shí)間片等。4.4.2Linux系統(tǒng)的進(jìn)程調(diào)度

Linux系統(tǒng)采用的調(diào)度算法簡(jiǎn)潔而高效。尤其是2.5版后的內(nèi)核采用了新的調(diào)度算法,在高負(fù)載和多CPU并行系統(tǒng)中執(zhí)行得極為出色。

1.進(jìn)程的調(diào)度信息

在Linux系統(tǒng)中,進(jìn)程的PCB中記錄了與進(jìn)程調(diào)度相關(guān)的信息,主要有:

(1)調(diào)度策略(policy):對(duì)進(jìn)程的調(diào)度算法。決定了調(diào)度程序應(yīng)如何調(diào)度該進(jìn)程。Linux系統(tǒng)將進(jìn)程分為實(shí)時(shí)進(jìn)程與普通(非實(shí)時(shí))進(jìn)程兩類,分別采用不同的調(diào)度策略。實(shí)時(shí)進(jìn)程是那些對(duì)響應(yīng)時(shí)間要求很高的進(jìn)程,如視頻與音頻應(yīng)用、過(guò)程控制和數(shù)據(jù)采集等,系統(tǒng)優(yōu)先響應(yīng)它們對(duì)CPU的要求;對(duì)普通進(jìn)程則采用優(yōu)先級(jí)+時(shí)間片輪轉(zhuǎn)的調(diào)度策略,以兼顧系統(tǒng)的響應(yīng)速度、公平性和整體效率。

(2)實(shí)時(shí)優(yōu)先級(jí)(rt_priority):實(shí)時(shí)進(jìn)程的優(yōu)先級(jí),標(biāo)志實(shí)時(shí)進(jìn)程優(yōu)先權(quán)的高低,取值范圍為1(最高)~99(最低)。

(3)靜態(tài)優(yōu)先級(jí)(static_prio):進(jìn)程的基本優(yōu)先級(jí)。進(jìn)程在創(chuàng)建之初被賦予了一個(gè)表示優(yōu)先程度的“nice數(shù)”(見10.6.2小節(jié)),它決定了進(jìn)程的靜態(tài)優(yōu)先級(jí)。靜態(tài)優(yōu)先級(jí)的取值范圍為100(最高)~139(最低),它是計(jì)算時(shí)間片的依據(jù)。

(4)動(dòng)態(tài)優(yōu)先級(jí)(prio):普通進(jìn)程的實(shí)際優(yōu)先級(jí)。它是對(duì)靜態(tài)優(yōu)先級(jí)的調(diào)整,隨進(jìn)程的運(yùn)行狀況而變化,取值范圍為100(最高)~139(最低)。

(5)時(shí)間片(time_slice):進(jìn)程當(dāng)前剩余的時(shí)間片。時(shí)間片的初始大小取決于進(jìn)程的靜態(tài)優(yōu)先級(jí),優(yōu)先級(jí)越高則時(shí)間片越長(zhǎng)。而后,隨著進(jìn)程的運(yùn)行,時(shí)間片不斷減少。時(shí)間片減為0的進(jìn)程將不會(huì)被調(diào)度,直到它再次獲得新的時(shí)間片。

進(jìn)程的調(diào)度策略和優(yōu)先級(jí)等是在進(jìn)程創(chuàng)建時(shí)從父進(jìn)程那里繼承來(lái)的,不過(guò)用戶可以通過(guò)系統(tǒng)調(diào)用改變它們。setpriority()和nice()用于設(shè)置靜態(tài)優(yōu)先級(jí);sched_setparam()用于設(shè)置實(shí)時(shí)優(yōu)先級(jí);sched_setscheduler()用于設(shè)置調(diào)度策略和參數(shù)。

2.調(diào)度函數(shù)和隊(duì)列

Linux系統(tǒng)中用于實(shí)現(xiàn)進(jìn)程調(diào)度的程序是內(nèi)核函數(shù)schedule()。該函數(shù)的功能是按照預(yù)定的策略在可執(zhí)行進(jìn)程中選擇一個(gè)進(jìn)程,切換CPU現(xiàn)場(chǎng)使之運(yùn)行。

調(diào)度程序中最基本的數(shù)據(jù)結(jié)構(gòu)是可執(zhí)行隊(duì)列runqueue。每個(gè)CPU都有一個(gè)自己的可執(zhí)行隊(duì)列,它包含了所有等待該CPU的可執(zhí)行進(jìn)程。runqueue結(jié)構(gòu)中設(shè)有一個(gè)curr指針,指向正在使用CPU的進(jìn)程。進(jìn)程切換時(shí),curr指針也跟著變化。舊版本的調(diào)度程序(2.4版內(nèi)核)在選擇進(jìn)程時(shí)需要遍歷整個(gè)可執(zhí)行隊(duì)列,用的時(shí)間隨進(jìn)程數(shù)量的增加而增加,最壞時(shí)可能達(dá)到O(n)復(fù)雜度級(jí)別。新內(nèi)核(2.6版內(nèi)核)改進(jìn)了調(diào)度的算法和數(shù)據(jù)結(jié)構(gòu),使算法的復(fù)雜度達(dá)到O(1)級(jí)(最優(yōu)級(jí)別),故稱為O(1)算法。

新內(nèi)核的runqueue隊(duì)列結(jié)構(gòu)中實(shí)際包含了多個(gè)進(jìn)程隊(duì)列,它們將進(jìn)程按優(yōu)先級(jí)劃分,相同優(yōu)先級(jí)的鏈接在一起,成為一個(gè)優(yōu)先級(jí)隊(duì)列。所有優(yōu)先級(jí)隊(duì)列的頭地址都記錄在一個(gè)優(yōu)先級(jí)數(shù)組中,按優(yōu)先級(jí)順序排列。實(shí)時(shí)進(jìn)程的優(yōu)先級(jí)隊(duì)列在前(1~99),普通進(jìn)程的優(yōu)先級(jí)隊(duì)列在后(100~139)。當(dāng)進(jìn)程調(diào)度選擇進(jìn)程時(shí),只需在優(yōu)先級(jí)數(shù)組中選擇當(dāng)前最高優(yōu)先級(jí)隊(duì)列中的第1個(gè)進(jìn)程即可。無(wú)論進(jìn)程的多少,這個(gè)操作總可以在固定的時(shí)間內(nèi)完成,因而是O(1)級(jí)別的。影響調(diào)度算法效率的另一個(gè)操作是為進(jìn)程重新計(jì)算時(shí)間片。舊算法中,當(dāng)所有進(jìn)程的時(shí)間片用完后,調(diào)度程序遍歷可執(zhí)行隊(duì)列,逐個(gè)為它們重新賦予時(shí)間片,然后開始下一輪的執(zhí)行。當(dāng)進(jìn)程數(shù)目很多時(shí),這個(gè)過(guò)程會(huì)十分耗時(shí)。為克服這個(gè)弊端,新調(diào)度函數(shù)將每個(gè)優(yōu)先級(jí)隊(duì)列分為兩個(gè):活動(dòng)隊(duì)列和過(guò)期隊(duì)列?;顒?dòng)隊(duì)列包含了那些時(shí)間片未用完的進(jìn)程,過(guò)期隊(duì)列包含了那些時(shí)間片用完的進(jìn)程。相應(yīng)地,在runqueue中設(shè)置了兩個(gè)優(yōu)先級(jí)數(shù)組,一個(gè)是活動(dòng)數(shù)組active,它記錄了所有活動(dòng)隊(duì)列的指針;另一個(gè)是過(guò)期數(shù)組expired,它記錄了所有過(guò)期隊(duì)列的指針。當(dāng)一個(gè)進(jìn)程進(jìn)入可執(zhí)行態(tài)時(shí),它被按照優(yōu)先級(jí)放入一個(gè)活動(dòng)隊(duì)列中;當(dāng)進(jìn)程的時(shí)間片耗完時(shí),它會(huì)被賦予新的時(shí)間片并轉(zhuǎn)移到相應(yīng)的過(guò)期隊(duì)列中。當(dāng)所有活動(dòng)隊(duì)列都為空時(shí),只需將active和expired數(shù)組的指針互換,過(guò)期隊(duì)列就成為活動(dòng)隊(duì)列。這個(gè)操作也是O(1)級(jí)別的。

可以看出,新調(diào)度的實(shí)現(xiàn)策略是用復(fù)雜的數(shù)據(jù)結(jié)構(gòu)來(lái)?yè)Q取算法的高效率的。

3.?Linux的進(jìn)程調(diào)度策略

進(jìn)程調(diào)度在選擇進(jìn)程時(shí),首先在可執(zhí)行隊(duì)列中尋找優(yōu)先級(jí)最高的進(jìn)程。由于實(shí)時(shí)進(jìn)程的優(yōu)先級(jí)(1~99)總是高于普通進(jìn)程(100~139),所以實(shí)時(shí)進(jìn)程永遠(yuǎn)優(yōu)先于普通進(jìn)程。選中進(jìn)程后,根據(jù)PCB中policy的值確定該進(jìn)程的調(diào)度策略來(lái)進(jìn)行調(diào)度。在schedule()函數(shù)中實(shí)現(xiàn)了3種調(diào)度策略,即先進(jìn)先出法,時(shí)間片輪轉(zhuǎn)法和普通調(diào)度法。

1)先進(jìn)先出法

先進(jìn)先出(FIFO,F(xiàn)irstInFirstOut)調(diào)度算法用于實(shí)時(shí)進(jìn)程,采用FIFO策略的實(shí)時(shí)進(jìn)程就緒后,按照優(yōu)先級(jí)rt_priority加入到相應(yīng)的活動(dòng)隊(duì)列的隊(duì)尾。調(diào)度程序按優(yōu)先級(jí)依次調(diào)度各個(gè)進(jìn)程運(yùn)行,具有相同優(yōu)先級(jí)的進(jìn)程采用FIFO算法。投入運(yùn)行的進(jìn)程將一直運(yùn)行,直到進(jìn)入僵死態(tài)、睡眠態(tài)或者是被具有更高實(shí)時(shí)優(yōu)先級(jí)的進(jìn)程奪去CPU。

FIFO算法實(shí)現(xiàn)簡(jiǎn)單,但在一些特殊情況下有欠公平。比如,一個(gè)運(yùn)行時(shí)間很短的進(jìn)程排在了一個(gè)運(yùn)行時(shí)間很長(zhǎng)的進(jìn)程之后,它可能要花費(fèi)比運(yùn)行時(shí)間長(zhǎng)很多倍的時(shí)間來(lái)等待。

2)時(shí)間片輪轉(zhuǎn)法

時(shí)間片輪轉(zhuǎn)(RR,RoundRobin)算法也是用于實(shí)時(shí)進(jìn)程,它的基本思想是給每個(gè)實(shí)時(shí)進(jìn)程分配一個(gè)時(shí)間片,然后按照它們的優(yōu)先級(jí)rt_priority加入到相應(yīng)的活動(dòng)隊(duì)列中。調(diào)度程序按優(yōu)先級(jí)依次調(diào)度,具有相同優(yōu)先級(jí)的進(jìn)程采用輪換法,每次運(yùn)行一個(gè)時(shí)間片。時(shí)間片的長(zhǎng)短取決于其靜態(tài)優(yōu)先級(jí)static_prio。當(dāng)一個(gè)進(jìn)程的時(shí)間片用完,它就要讓出CPU,重新計(jì)算時(shí)間片后加入到同一活動(dòng)隊(duì)列的隊(duì)尾,等待下一次運(yùn)行。RR算法也采用了優(yōu)先級(jí)策略。在進(jìn)程的運(yùn)行過(guò)程中,如果有更高優(yōu)先級(jí)的實(shí)時(shí)進(jìn)程就緒,則調(diào)度程序就會(huì)中止當(dāng)前進(jìn)程而去響應(yīng)高優(yōu)先級(jí)的進(jìn)程。

相比FIFO來(lái)說(shuō),RR算法在追求響應(yīng)速度的同時(shí)還兼顧到公平性。

3)普通調(diào)度法

普通調(diào)度法(NORMAL,NormalScheduling)用于普通進(jìn)程的調(diào)度。每個(gè)進(jìn)程擁有一個(gè)靜態(tài)優(yōu)先級(jí)和一個(gè)動(dòng)態(tài)優(yōu)先級(jí)。動(dòng)態(tài)優(yōu)先級(jí)是基于靜態(tài)優(yōu)先級(jí)調(diào)整得到的實(shí)際優(yōu)先級(jí),它與進(jìn)程的平均睡眠時(shí)間有關(guān),進(jìn)程睡眠的時(shí)間越長(zhǎng)則其動(dòng)態(tài)優(yōu)先級(jí)越高。調(diào)整優(yōu)先級(jí)的目的是為了提高對(duì)交互式進(jìn)程的響應(yīng)性。

NORMAL算法與RR算法類似,都是采用優(yōu)先級(jí)+時(shí)間片輪轉(zhuǎn)的調(diào)度方法。進(jìn)程按其優(yōu)先級(jí)prio被鏈入相應(yīng)的活動(dòng)隊(duì)列中。調(diào)度程序按優(yōu)先級(jí)順序依次調(diào)度各個(gè)隊(duì)列中的進(jìn)程,每次運(yùn)行一個(gè)時(shí)間片。一個(gè)進(jìn)程的時(shí)間片用完后,內(nèi)核重新計(jì)算它的動(dòng)態(tài)優(yōu)先級(jí)和時(shí)間片,然后將它加入到相應(yīng)的過(guò)期隊(duì)列中。與RR算法的不同之處在于,普通進(jìn)程的時(shí)間片用完后被轉(zhuǎn)入過(guò)期隊(duì)列中,它要等到所有活動(dòng)隊(duì)列中的進(jìn)程都運(yùn)行完后才會(huì)獲得下一輪執(zhí)行機(jī)會(huì)。而RR算法的進(jìn)程始終在活動(dòng)隊(duì)列中,直到其執(zhí)行完畢。這保證了實(shí)時(shí)進(jìn)程不會(huì)被比它的優(yōu)先級(jí)低的進(jìn)程打斷??梢钥闯?,RR算法注重優(yōu)先級(jí)順序,只在每級(jí)內(nèi)采用輪轉(zhuǎn);而NORMAL算法注重的是輪轉(zhuǎn),在每輪中采用優(yōu)先級(jí)順序。

4.進(jìn)程調(diào)度的時(shí)機(jī)

當(dāng)需要切換進(jìn)程時(shí),進(jìn)程調(diào)度程序就會(huì)被調(diào)用。引發(fā)進(jìn)程調(diào)度的時(shí)機(jī)有下面幾種:

(1)當(dāng)前進(jìn)程將轉(zhuǎn)入睡眠態(tài)或僵死態(tài)。

(2)一個(gè)更高優(yōu)先級(jí)的進(jìn)程加入到可執(zhí)行隊(duì)列中。

(3)當(dāng)前進(jìn)程的時(shí)間片用完。

(4)進(jìn)程從核心態(tài)返回到用戶態(tài)。從本質(zhì)上看,這些情況可以歸結(jié)為兩類時(shí)機(jī),一是進(jìn)程本身自動(dòng)放棄CPU而引發(fā)的調(diào)度,這是上述第1種情況。這時(shí)的進(jìn)程是主動(dòng)退出CPU,轉(zhuǎn)入睡眠或僵死態(tài)。二是進(jìn)程由核心態(tài)轉(zhuǎn)入用戶態(tài)時(shí)發(fā)生調(diào)度,包括上述后3種情況。這類調(diào)度發(fā)生最為頻繁。當(dāng)進(jìn)程執(zhí)行系統(tǒng)調(diào)用或中斷處理后返回,都是由核心態(tài)轉(zhuǎn)入用戶態(tài)。時(shí)間片用完是由系統(tǒng)的時(shí)鐘中斷引起的中斷處理過(guò)程,而新進(jìn)程加入可執(zhí)行隊(duì)列也是由內(nèi)核模塊處理的,因此也都會(huì)在處理完后從內(nèi)核態(tài)返回到用戶態(tài)。

Linux系統(tǒng)是搶占式多任務(wù)系統(tǒng),上述情況除了第1種是進(jìn)程主動(dòng)調(diào)用調(diào)度程序放棄CPU的,其他情況下都是由系統(tǒng)強(qiáng)制進(jìn)行重新調(diào)度的,這就是CPU搶占(preemption)。在必要時(shí)搶占CPU可以保證系統(tǒng)具有很好的響應(yīng)性。為了標(biāo)志何時(shí)需要重新進(jìn)行進(jìn)程調(diào)度,系統(tǒng)在進(jìn)程的PCB中設(shè)置了一個(gè)need_resched標(biāo)志位,為1時(shí)表示需要重新調(diào)度。當(dāng)某個(gè)進(jìn)程的時(shí)間片耗盡,或有高優(yōu)先級(jí)進(jìn)程加入到可執(zhí)行隊(duì)列中,或進(jìn)程從系統(tǒng)調(diào)用或中斷處理中返回前,都會(huì)設(shè)置這個(gè)標(biāo)志。每當(dāng)系統(tǒng)從核心態(tài)返回用戶態(tài)時(shí),內(nèi)核都會(huì)檢查need_resched標(biāo)志,如果已被設(shè)置,內(nèi)核將調(diào)用調(diào)度函數(shù)進(jìn)行重新調(diào)度。

4.5進(jìn)程的互斥與同步

多個(gè)進(jìn)程在同一系統(tǒng)中并發(fā)執(zhí)行,共享系統(tǒng)資源,因此它們不是孤立存在的,而是會(huì)互相影響或互相合作。為保證進(jìn)程不因競(jìng)爭(zhēng)資源而導(dǎo)致錯(cuò)誤的執(zhí)行結(jié)果,需要通過(guò)某種手段實(shí)現(xiàn)相互制約。這種手段就是進(jìn)程的互斥與同步。4.5.1進(jìn)程的互斥與同步

并發(fā)進(jìn)程彼此間會(huì)產(chǎn)生相互制約的關(guān)系。進(jìn)程之間的制約關(guān)系有兩種方式:一是進(jìn)程的同步,即相關(guān)進(jìn)程為協(xié)作完成同一任務(wù)而引起的直接制約關(guān)系;二是進(jìn)程的互斥,即進(jìn)程間因競(jìng)爭(zhēng)系統(tǒng)資源而引起的間接制約關(guān)系。

1.臨界資源與臨界區(qū)

臨界資源(criticalresource)是一次僅允許一個(gè)進(jìn)程使用的資源。例如,共享的打印機(jī)就是一種臨界資源。當(dāng)一個(gè)進(jìn)程在打印時(shí),其他進(jìn)程必須等待,否則會(huì)使各進(jìn)程的輸出混在一起。共享內(nèi)存、緩沖區(qū)、共享的數(shù)據(jù)結(jié)構(gòu)或文件等都屬于臨界資源。

臨界區(qū)(criticalregion)是程序中訪問(wèn)臨界資源的程序片段。劃分臨界區(qū)的目的是為了明確進(jìn)程的互斥點(diǎn)。當(dāng)進(jìn)程運(yùn)行在臨界區(qū)之外時(shí),不會(huì)引發(fā)競(jìng)爭(zhēng)條件。而當(dāng)進(jìn)程運(yùn)行在臨界區(qū)內(nèi)時(shí),它正在訪問(wèn)臨界資源,此時(shí)應(yīng)阻止其他進(jìn)程進(jìn)入同一資源的臨界區(qū)。在4.1.1小節(jié)中描述了一個(gè)停車場(chǎng)車位計(jì)數(shù)器的例子(見圖4?)。當(dāng)A、B兩個(gè)進(jìn)程同時(shí)修改計(jì)數(shù)器C時(shí)就會(huì)發(fā)生更新錯(cuò)誤,因此C是一個(gè)臨界資源,而程序A和B中訪問(wèn)C的程序段就稱為臨界區(qū),如圖4-12所示。圖4-12臨界資源與臨界區(qū)

2.進(jìn)程的互斥與同步

因共享臨界資源而發(fā)生錯(cuò)誤,其原因在于多個(gè)進(jìn)程訪問(wèn)該資源的操作穿插進(jìn)行。要避免這種錯(cuò)誤,關(guān)鍵是要用某種方式來(lái)阻止多個(gè)進(jìn)程同時(shí)訪問(wèn)臨界資源,這就是互斥。

進(jìn)程的互斥(mutex)就是禁止多個(gè)進(jìn)程同時(shí)進(jìn)入各自的訪問(wèn)同一臨界資源的臨界區(qū),以保證對(duì)臨界資源的排它性使用。以停車場(chǎng)車位計(jì)數(shù)器為例,當(dāng)進(jìn)程A運(yùn)行在它的(A的)臨界區(qū)內(nèi)時(shí),進(jìn)程B不能進(jìn)入它的(B的)臨界區(qū)執(zhí)行,進(jìn)程B必須等待,直到A離開A的臨界區(qū)后,B才可進(jìn)入B的臨界區(qū)運(yùn)行。進(jìn)程的同步(synchronization)是指

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論