進程管理
進程的基本概念
程序的順序執行及其特征
-
程序的順序執行:僅當前一操作(程序段)執行完后,才能執行后續操作。
-
程序順序執行時的特征:順序性,封閉性,可再見性。
前趨圖
前趨圖(Precedence Graph)是一個有向無循環圖,記為DAG(Directed Acycilc Graph),用于描述進程之間執行的前后關系。圖中的每一個節點可用于描述一個程序段或進程,乃至一條語句。結點間的有向邊則用于表示兩個結點之間存在的偏序(Partial Order)或前趨關系(Precedence Relation)“→”
→={(Pi, Pj)|Pi must complete before Pj may start}, 如果(Pi, Pj)∈→,可寫成Pi→Pj,稱Pi是Pj的直接前趨,而稱Pj是Pi的直接后繼。在前趨圖中,把沒有前趨的結點稱為初始結點(Initial Node),把沒有后繼的結點稱為終止結點(Final Node)
程序的并發執行及其特征
- 程序的并發執行
-
程序并發執行時的特征
-
間斷性
-
失去封閉性
-
不可再現性
進程的特征和狀態
進程的特征和定義
結構特征:
-
動態性
-
并發性
-
獨立性
-
異步性
較典型的進程定義:
-
進程是程序的一次執行。
-
進程是一個程序及其數據在處理機上順序執行時所發生的活動。
-
進程是出現在一個數據集合上運行的過程,它是系統進行資源分配和調度的一個獨立單位。
進程的三種基本狀態
-
就緒(Ready)狀態
-
執行狀態
-
阻塞狀態
掛起狀態
引起掛起狀態的原因:
-
終端用戶的請求;
-
父進程請求;
-
負責調節的需求;
-
操作系統的需要
進程狀態的轉換
-
活動就緒-->靜止就緒
-
活動阻塞-->靜止阻塞
-
靜止就緒-->活動就緒
-
靜止阻塞-->活動阻塞
具有掛起狀態的進程狀態圖
進程控制塊(PCB)
進程控制塊的作用:進程控制塊的作用是使一個在多道程序環境下不能獨立運行的程序(含數據),成為一個能獨立運行的基本單位,一個能與其它進程并發執行的進程。
進程控制塊中的信息
-
進程標識符: 進程標識符用于惟一地標識一個進程。一個進程通常有兩種標識符:
-
內部標識符:在所有的操作系統中,都為每一個進程賦予一個惟一的數字標識符,它通常是一個進程的序號。 設置內部標識符主要是為了方便系統使用
-
外部標識符:它由創建者提供,通常是由字母、數字組成,往往是由用戶(進程)在訪問該進程時使用。為了描述進程的家族關系, 還應設置父進程標識及子進程標識。此外,還可設置用戶標識,以指示擁有該進程的用戶
-
-
處理機狀態:處理機狀態信息主要是由處理機的各種寄存器中的內容組成的。
-
進度調度信息:在PCB中還存放一些與進程調度和進程對換有關的信息,包括:
-
進程狀態,指明進程的當前狀態,作為進程調度和對換時的依據
-
進程優先級,用于描述進程使用處理機的優先級別的一個整數,優先級別高的進程應優先獲得處理機
-
進程調度所需的其它信息,它們與所采用的進程調度算法有關。
-
事件,是指進程由執行狀態轉變為阻塞狀態所等待發生的事件,即阻塞原因。
-
-
進程控制信息
-
程序和數據的地址,是指進程的程序和數據所在的內存或外存地(首)址,以便再調度到該進程執行時,能從PCB中找到其程序和數據
-
進程同步和通信機制,指實現進程同步和進程通信時必需的機制,如信息隊列指針、信號量等,他們可能全部或部分地放在PCB中
-
資源清單,是一張列出了除CPU以外的、進程所需的全部資源及已經分配到該進程的資源的清單。
-
鏈接指針,它給出了本進程(PCB)所在隊列中的下一個進程的PCB的首地址。
-
進程控制塊的組織方式
- 鏈接方式
PCB鏈表隊列示意圖:
- 索引方式
進程控制
進程的創建
進程圖(Process Graph)
引起創建進程的事件
- 用戶登錄
- 作業調度
- 提供服務
- 應用請求
進程的創建
- 申請空白PCB
- 為新進程分配資源
- 初始化進程控制塊
- 將新進程插入就緒隊列,如果進程就緒隊列能夠接納新進程,便將新進程插入就緒隊列。
進程的終止
引起進程終止的事件
- 正常結束 在任何計算機系統中,都應有一個用于表示進程已經運行完成的指示。
- 異常結束 在進程運行期間,由于出現某些錯誤和故障而迫使進程終止。
- 越界錯誤。這是指程序所訪問的存儲區,已越出該進程的區域;
- 保護錯。進程試圖去訪問一個不允許訪問的資源或文件,或者以不適當的方式進行訪問,例如,進程試圖去寫一個只讀文件;
- 非法指令。程序試圖去執行一條不存在的指令。出現該錯誤的原因,可能是程序錯誤地轉移到數據區,把數據當成了指令;
- 特權指令錯。用戶進程試圖去執行一條只允許OS執行的指令;
- 運行超時。
- 等待超時。
- 算術運算錯。進程試圖去執行一個被禁止的運算,例如,被0除;
- I/O故障。這是指在I/O過程中發生了錯誤等
- 外界干預 外界干預并非指在本進程運行中出現了異常事件,而是指進程應外界的請求而終止運行。
- 操作員或操作系統干預
- 父進程請求
- 父進程終止
進程的終止過程
- 根據被終止進程的標識符,從PCB集合中檢索出該進程的PCB,從中讀出該進程的狀態
- 若被終止進程正處于執行狀態,應立即終止該進程的執行,并置調度標志為真,用于指示該進程被終止后應重新進行調度
- 若該進程還有子孫進程,還應將其所有子孫進程予以終止,以防他們成為不可控的進程
- 將被終止進程所擁有的全部資源,或者歸還給其父進程, 或者歸還給系統
- 將被終止進程(它的PCB)從所在隊列(或鏈表)中移出, 等待其他程序來搜集信息
進程的阻塞與喚醒
引起進程阻塞和喚醒的事件
- 請求系統服務
- 啟動某種操作
- 新數據尚未到達
- 無工作可做
進程阻塞過程
正在執行的進程,當發現上述某事件時,由于無法繼續執行,于是進程便通過調用阻塞原語block把自己阻塞。可見,進程的阻塞是進程自身的一種主動行為。進入block過程后,由于此時該進程還處于執行狀態,所以應先立即停止執行,把進程控制塊中的現行狀態由“執行”改為阻塞,并將PCB插入阻塞隊列。如果系統中設置了因不同事件而阻塞的多個阻塞隊列,則應將本進程插入到具有相同事件的阻塞(等待)隊列。 最后,轉調度程序進行重新調度,將處理機分配給另一就緒進程,并進行切換,亦即,保留被阻塞進程的處理機狀態(在PCB中),再按新進程的PCB中的處理機狀態設置CPU的環境。
進程喚醒過程
當被阻塞進程所期待的事件出現時,如I/O完成或其所期待的數據已經到達,則由有關進程(比如,用完并釋放了該I/O設備的進程)調用喚醒原語wakeup( ),將等待該事件的進程喚醒。
原語執行的過程是:首先把被阻塞的進程從等待該事件的阻塞隊列中移出,將其PCB中的現行狀態由阻塞改為就緒,然后再將該PCB插入到就緒隊列中
進程的掛起與激活
- 進程的掛起 當被阻塞進程所期待的事件出現時,如I/O完成或其所期待的數據已經到達,則由有關進程(比如,用完并釋放了該I/O設備的進程)調用喚醒原語wakeup( ),將等待該事件的進程喚醒。 >喚醒原語執行的過程是:首先把被阻塞的進程從等待該事件的阻塞隊列中移出,將其PCB中的現行狀態由阻塞改為就緒,然后再將該PCB插入到就緒隊列中
- 進程的激活過程 當發生激活進程的事件時,例如,父進程或用戶進程請求激活指定進程,若該進程駐留在外存而內存中已有足夠的空間時,則可將在外存上處于靜止就緒狀態的進程換入內存。這時,系統將利用激活原語active( )將指定進程激活。 >激活原語先將進程從外存調入內存,檢查該進程的現行狀態,若是靜止就緒,便將之改為活動就緒;若為靜止阻塞便將之改為活動阻塞。假如采用的是搶占調度策略,則每當有新進程進入就緒隊列時,應檢查是否要進行重新調度,即由調度程序將被激活進程與當前進程進行優先級的比較,如果被激活進程的優先級更低,就不必重新調度;否則,立即剝奪當前進程的運行,把處理機分配給剛被激活的進程。
進程同步
進程同步的主要任務是對多個相關進程在執行次序上進行協調,以使并發執行的諸進程之間能有效地共享資源和相互合作,從而使程序的執行具有可再現性。
進程同步的基本概念
- 兩種形式的制約關系
- 間接相互制約關系,源于資源共享。
- 直接相互制約關系,源于進程間的合作。
-
臨界資源(Critical Resouce) 許多硬件資源如打印機、磁帶機等,都屬于臨界資源,諸進程間應采取互斥方式,實現對這種資源的共享。
生產者-消費者(producer-consumer)問題:有一群生產者進程在生產產品,并將這些產品提供給消費者進程去消費。為使生產者進程與消費者進程能并發執行,在兩者之間設置了一個具有n個緩沖區的緩沖池,生產者進程將它所生產的產品放入一個緩沖區中; 消費者進程可從一個緩沖區中取走產品去消費。盡管所有的生產者進程和消費者進程都是以異步方式運行的,但它們之間必須保持同步,即不允許消費者進程到一個空緩沖區去取產品;也不允許生產者進程向一個已裝滿產品且尚未被取走的緩沖區中投放產品。
我們可利用一個數組來表示上述的具有n個(0,1,…,n-1)緩沖區的緩沖池。用輸入指針in來指示下一個可投放產品的緩沖區,每當生產者進程生產并投放一個產品后,輸入指針加1;用一個輸出指針out來指示下一個可從中獲取產品的緩沖區,每當消費者進程取走一個產品后,輸出指針加1。 由于這里的緩沖池是組織成循環緩沖的,故應把輸入指針加1表示成 in∶=(in+1)mod n;輸出指針加1表示成out∶=(out+1) mod n。當(in+1) mod n=out時表示緩沖池滿;而in=out則表示緩沖池空。此外,還引入了一個整型變量counter, 其初始值為0。每當生產者進程向緩沖池中投放一個產品后,使counter加1;反之,每當消費者進程從中取走一個產品時, 使counter減1。生產者和消費者兩進程共享下面的變量:
Var n, integer; type item=…; var buffer:array[0, 1, …, n-1] of item; in, out: 0, 1, …, n-1; counter: 0, 1, …, n;
指針in和out初始化為1。在生產者和消費者進程的描述中,no-op是一條空操作指令,while condition do no-op語句表示重復的測試條件(condication),重復測試應進行到該條件變為false(假),即到該條件不成立時為止。在生產者進程中使用一局部變量nextp,用于暫時存放每次剛生產出來的產品;而在消費者進程中,則使用一個局部變量nextc,用于存放每次要消費的產品。 producer: repeat ... produce an item in nextp; ... while counter=n do no-op; buffer[in]:=nextp; in:=(in+1)mod n; counter: =counter+1; until false; consumer: repeat while counter=0 do no-op; nextc: =buffer[out]; out: =(out+1) mod n; counter: =counter-1; consumer the item in nextc; until false;
雖然上面的生產者程序和消費者程序,在分別看時都是正確的,而且兩者在順序執行時其結果也會是正確的,但若并發執行時,就會出現差錯,問題就在于這兩個進程共享變量counter。生產者對它做加1操作,消費者對它做減1操作,這兩個操作在用機器語言實現時, 常可用下面的形式描述:
register 1:=counter; register 2:=counter; register1:=register 1+1; register 2:=register 2-1; counter:=register 1; counter: =register 2;
假設:counter的當前值是5。如果生產者進程先執行左列的三條機器語言語句,然后消費者進程再執行右列的三條語句, 則最后共享變量counter的值仍為5;反之,如果讓消費者進程先執行右列的三條語句,然后再讓 生產者進程執行左列的三條語句,counter值也還是5,但是,如果按下述順序執行: register 1 :=counter; (register 1=5) register 1 :=register 1+1; (register 1=6) register 2 :=counter; (register 2=5) register 2 :=register 2-1; (register 2=4) counter :=register 1; (counter=6) counter :=register 2; (counter=4)
正確的counter值應該是5,但是現在是4.為了預防產生這種錯誤,解決此問題的關鍵是應把變量counter作為臨界資源處理,即,令生產者進程和消費者進程互斥地訪問變量counter。
-
臨界區(critical section) 可把一個訪問臨界資源的循環進程描述如下:?
-
同步機制應遵循的規則
- 空閑讓進
- 忙則等待
- 有限等待
- 讓權等待
信號量機制
整型信號量
最初由Dijkstra把整型信號量定義為一個用于表示資源數目的整型量S,除初始化外,僅能通過兩個標準的原子操作(Atomic Operation) wait(S)和signal(S)來訪問。 這兩個操作被分別稱為P、V操作。 wait和signal操作可描述為:
wait(S): while S≤0 do no-op;S:=S-1;
signal(S):S:=S+1;
記錄型信號量
在信號量機制中,除了需要一個用于代表資源數目的整型變量value外,還應增加一個進程鏈表L,用于鏈接等待進程。記錄型信號量是由于它采用了記錄型的數據結構而得名的。它所包含的上述兩個數據項可描述為:
type semaphore=recordvalue:integer;L:list of process;end
相應地,wait(S)和signal(S)操作可描述為:
procedure wait(S)var S: semaphore;beginS.value∶ =S.value-1;if S.value<0 thenblock(S,L)end
procedure signal(S)var S: semaphore;beginS.value∶ =S.value+1;if S.value≤0 thenwakeup(S,L);end
在記錄型信號量機制中,S.value的初值表示系統中某類資源的數目, 因而又稱為資源信號量,對它的每次wait操作,意味著進程請求一個單位的該類資源,因此描述為S.value∶ =S.value-1; 當S.value<0時,表示該類資源已分配完畢,因此進程應調用block原語,進行自我阻塞,放棄處理機,并插入到信號量鏈表S.L中。可見,該機制遵循了“讓權等待”準則。 此時S.value的絕對值表示在該信號量鏈表中已阻塞進程的數目。 對信號量的每次signal操作,表示執行進程釋放一個單位資源,故S.value∶ =S.value+1操作表示資源數目加1。 若加1后仍是S.value≤0,則表示在該信號量鏈表中,仍有等待該資源的進程被阻塞,故還應調用wakeup原語,將S.L鏈表中的第一個等待進程喚醒。如果S.value的初值為1,表示只允許一個進程訪問臨界資源,此時的信號量轉化為互斥信號量。
AND型信號量
AND同步機制的基本思想是:將進程在整個運行過程中需要的所有資源,一次性全部地分配給進程,待進程使用完后再一起釋放。只要尚有一個資源未能分配給進程,其它所有可能為之分配的資源,也不分配給他。亦即,對若干個臨界資源的分配,采取原子操作方式:要么全部分配到進程,要么一個也不分配。 由死鎖理論可知,這樣就可避免上述死鎖情況的發生。為此,在wait操作中,增加了一個“AND”條件,故稱為AND同步,或稱為同時wait操作, 即Swait(Simultaneous wait)定義如下:
Swait(S1, S2, …, Sn)
if Si≥1 and … and Sn≥1 thenfor i∶ =1 to n doSi∶=Si-1;endfor
elseplace the process in the waiting queue associated with the first Si found with Si<1, and set the program count of this process to the beginning of Swait operation
endif
Ssignal(S1, S2, …, Sn)for i∶ =1 to n doSi=Si+1;Remove all the process waiting in the queue associated with Si into the ready queue.
endfor;
信號量集
一般“信號量集”的幾種特殊情況: (1) Swait(S, d, d)。 此時在信號量集中只有一個信號量S, 但允許它每次申請d個資源,當現有資源數少于d時,不予分配。 (2) Swait(S, 1, 1)。 此時的信號量集已蛻化為一般的記錄型信號量(S>1時)或互斥信號量(S=1時)。 (3) Swait(S, 1, 0)。這是一種很特殊且很有用的信號量操作。當S≥1時,允許多個進程進入某特定區;當S變為0后,將阻止任何進程進入特定區。換言之,它相當于一個可控開關。
信號量的應用
- 利用信號量實現進程互斥 Var mutex:semaphore:=1; begin parbegin process 1: begin repeat wait(mutex); critical section signal(mutex); remainder seetion until false; end process 2: begin repeat wait(mutex); critical section signal(mutex); remainder section until false; end parend
- 利用信號量實現前趨關系 設有兩個并發執行的進程P1和P2.P1中有語句S1;P2中有語句S2。我們希望在S1執行后再執行S2,為實現這種前趨關系,我們只需使進程P1和P2共享一個公共信號值S,并賦予其初值為0,將signal(S)操作放在語句S1后面;而在S2語句前面插入wait(S)操作,即 在進程P1中,用S1: signal(S); 在進程P2中,用wait(S);S2; 由于S被初始化為0,這樣,若P2先執行必定阻塞,只有在進程P1執行完S1;signal(S);操作后使S增為1時,P2進程方能執行語句S2成功。
管程機制
管程(Monitors):一種新的進程同步工具 1. 管程的定義 管程由四部分組成: - 管程的名稱、 - 局部于管程內部的分享數據結構說明、 - 對該數據進行操作的一組過程、 - 對局部于管程內部的共享數據設置初始值的語句。
管程相當于圍墻,它把共享變量和對它進行操作的若干過程圍了起來,所有進程要訪問臨界資源時,都必須經過管程(相當于通過圍墻的門)才能進入,而管程每次只準許一個進程進入管程,從而實現了進程互斥。 管程的特性:
- 模塊化
- 抽象數據類型
- 信息掩蔽
2.條件變量 考慮一種情況:當一個進程調用了管程,在管程中時被阻塞或掛起,直到阻塞或掛起的原因解除,而在此期間,如果該進程不釋放管程,則其他進程無法進入管程,被迫長時間地等待。為了解決這個問題,引入了條件變量condition。對這些條件變量的訪問,只能在管程中進行。 管程中對每一個條件變量都需予以說明,其形式為:Var x,y:condition。對條件變量的操作僅僅是wait和signal,因此條件變量也是一種抽象數據類型,每個條件變量保存了一個鏈表,用來記錄因該條件變量而阻塞的所有進程,同時提供的兩個操作即可表示為x.wait和x.signal。其含義為
- x.wait:正在調用管程的進程因x條件需要被阻塞或掛起,則調用x.wait將自己插入到x條件的等待隊列上,并釋放管程,直到x條件變化。此時其他進程可以使用該管程。
- x.signal:正在調用管程的進程發現x條件發生了變化,則調用x.signal,重新啟動一個因x條件而阻塞或掛起的進程。如果存在多個這樣的進程,則選擇其中一個,如果沒有,則繼續執行原進程,而不產生任何結果。這和信號量機制中的signal操作不同,因為后者總要執行s:=s+1操作,因而總會改變信號量的狀態。 如果有進程Q因x條件處于阻塞狀態,當正在調用管程的進程P執行了x.signal操作后,進程Q被重新啟動了。此時兩個進程P和Q,如何確定那個執行,哪個等待,可采用下述兩種方式之一進行處理:
- P等待,直至Q離開管程或等待另一條件
- Q等待,直至P離開管程或等待另一條件
進程通信
信號量機制作為同步工具是卓有成效的,但作為通信工具,則不夠理想,主要表現在兩個方面:
- 效率低
- 通信對用戶不透明
本節所介紹的是高級進程通信,是指用戶可直接利用操作系統所提供的一組通信命令高效地傳送大量數據的一種通信方式。操作系 統隱藏了進程通信的實現細節。即通信過程對用戶是透明的,這樣就大大減少了通信程序編制上的復雜性。
進程通信的類型
目前,高級通信機制可歸結為三大類:共享存儲器系統、消息傳遞系統以及管道通信系統。 1. 共享存儲器系統 在共享存儲器系統(Shared-Memory System)中,相互通信的進程共享某些數據結構或共享數據存儲區,進程之間能夠通過這些空間進行通信。 1. 基于共享數據結構的通信方式。 在這種通信方式中,要求諸進程公用某些數據結構,借以實現諸進程間的信息交換。這種通信方式是低效的,只適于傳遞相對少量的數據。 2. 基于共享存儲區的通信方式 為了傳輸大量數據、在存儲器中劃出了一塊共享存儲區,諸進程可通過對共享存儲區中數據的讀或寫來實現通信。進程在通信前,先向系統申請獲得共享存儲區中的一個分區,并指定該分區的關鍵字;若系統已經給其他進程分配了這樣的分區,則將該分區的描述符返回給申請者,繼之,由申請者把獲得的共享存儲區連接到本進程中;此后,便可像讀、寫普通存儲器一樣地讀、寫該公用存儲分區。 2. 消息傳遞系統 消息傳遞系統(Message passing system)是當前應用最廣泛的一種進程間的通信機制。在該機制中,進程間的數據交換是以格式化的消息(message)為單位的;在計算機網絡中又把message稱為報文。程序員直接利用操作系統提供的一組通信命令(原語),不僅能實現大量數據的傳遞,而且還隱藏了通信的實現細節,是通信過程對用戶是透明的,從而大大減化了通信程序編制的復雜性。 3. 管道通信 所謂"管道",是指用于連接一個讀進程和一個寫進程以實現它們之間通信的一個共享文件,又名pipe文件。向管道(共享文件)提供輸入
線程
線程的基本概念
進程的操作
- 創建進程
- 撤消進程
- 進程切換
線程的屬性
- 輕型實體
- 獨立調度和分派的基本單位
- 可并行執行
- 共享進程資源
線程的狀態
狀態參數
在OS中的每一個線程都可以利用線程標識符和一組狀態參數進行描述。狀態參數通常有這樣幾項:
- 寄存器狀態,包括程序計數器PC和堆棧指針中的內容;
- 堆棧,在堆棧中通常保存有局部變量和返回地址
- 線程運行狀態,用于描述線程正處于何種運行狀態
- 優先級,描述線程執行的優先程序
- 線程專有存儲器,用于保存線程自己的局部變量拷貝
- 信號屏蔽,即對某些信號加以屏蔽
線程運行狀態
線程在運行時,具有三種基本狀態:
- 執行狀態,表示線程正獲得處理機而運行;
- 就緒狀態,指線程已具備了各種執行條件,一旦獲得CPU便可執行的狀態
- 阻塞狀態,指線程在執行中因某事件而受阻,處于暫停執行時的狀態
線程的創建和終止
在多線程OS環境下,應用程序在啟動時,通常僅有一個線程在執行,該線程被人們稱為“初始化線程”。它可根據需要再去創建若干個線程。在創建新線程時,需要利用一個線程創建函數(或系統調用),并提供相應的參數,如指向線程主程序的入口指針、堆棧的大小,以及用于調度的優先級等。在線程創建函數執行完后,將返回一個線程標識符供以后使用。 終止線程的方式有兩種:一種是在線程完成了自己的工作后自愿退出;另一種是線程在運行中出現錯誤或由于某種原因而被其它線程強行終止。
多線程OS中的進程
在多線程OS中,進程是作為擁有系統資源的基本單位,通常的進程都包含多個線程并為它們提供資源,但此時的進程就不再作為一個執行的實體。 多線程OS中的進程有以下屬性: 1. 作為系統資源分配的單位 2. 可包括多個線程 3. 進程不是一個可執行的實體
線程間的同步和通信
- 互斥鎖(mutex) 互斥鎖是一種比較簡單的、用于實現進程間對資源互斥訪問的機制。由于操作互斥鎖的時間和空間開鎖都較低, 因而較適合于高頻度使用的關鍵共享數據和程序段。互斥鎖可以有兩種狀態, 即開鎖(unlock)和關鎖(lock)狀態。 相應地,可用兩條命令(函數)對互斥鎖進行操作。其中的關鎖lock操作用于將mutex關上,開鎖操作unlock則用于打開mutex。
- 條件變量 每一個條件變量通常都與一個互斥鎖一起使用,亦即,在創建一個互斥鎖時便聯系著一個條件變量。單純的互斥鎖用于短期鎖定,主要是用來保證對臨界區的互斥進入。而條件變量則用于線程的長期等待, 直至所等待的資源成為可用的。 線程首先對mutex執行關鎖操作,若成功便進入臨界區,然后查找用于描述資源狀態的數據結構,以了解資源的情況。 只要發現所需資源R正處于忙碌狀態,線程便轉為等待狀態, 并對mutex執行開鎖操作后,等待該資源被釋放; 若資源處于空閑狀態,表明線程可以使用該資源,于是將該資源設置為忙碌狀態,再對mutex執行開鎖操作。 下面給出了對上述資源的申請(左半部分)和釋放(右半部分)操作的描述: Lock mutex Lock mutex check data structures; mark resource as free; while(resource busy); unlock mutex; wait(condition variable); wakeup(condition variable); mark resource as busy; unlock mutex;
- 信號量機制
- 私有信號量(private samephore) 當某線程需利用信號量來實現同一進程中各線程之間的同步時,可調用創建信號量的命令來創建一私用信號量,其數據結構是存放在應用程序的地址空間中。私用信號量屬于特定的進程所有,OS并不知道私用信號量的存在,因此,一旦發生私用信號量的占用者異常結束或正常結束,但并未釋放該信號量所占有空間的情況時,系統將無法使它恢復為0(空), 也不能將它傳送給下一個請求它的線程。
- 公有信號量(public samephore) 公用信號量是為實現不同進程間或不同進程中各線程之間的同步而設置的。由于它有著一個公開的名字供所有的進程使用,故而把它稱為公用信號量。其數據結構是存放在受保護的系統存儲區中,由OS為它分配空間并進行管理,故也稱為系統信號量。如果信號量的占有者在結束時未釋放該公用信號量,則OS會自動將該信號量空間回收,并通知下一進程。可見,公用信號量是一種比較安全的同步機制。 ##內核支持線程和用戶級線程
-
內核支持線程 這里所謂的內核支持線程,也都同樣是在內核的支持下運行的,即無論是用戶進程中的線程,還是系統進程中的線程,他們的創建、撤消和切換等,也是依靠內核實現的。此外,在內核空間還為每一個內核支持線程設置了一個線程控制塊, 內核是根據該控制塊而感知某線程的存在的,并對其加以控制。
-
用戶級線程 用戶級線程僅存在于用戶空間中。對于這種線程的創建、 撤消、線程之間的同步與通信等功能,都無須利用系統調用來實現。對于用戶級線程的切換,通常是發生在一個應用進程的諸多線程之間,這時,也同樣無須內核的支持。由于切換的規則遠比進程調度和切換的規則簡單,因而使線程的切換速度特別快。可見,這種線程是與內核無關的。
線程控制
內核支持線程的實現
用戶級線程的實現
- 運行時系統(Runtime System) 所謂“運行時系統”,實質上是用于管理和控制線程的函數(過程)的集合, 其中包括用于創建和撤消線程的函數、 線程同步和通信的函數以及實現線程調度的函數等。正因為有這些函數,才能使用戶級線程與內核無關。運行時系統中的所有函數都駐留在用戶空間,并作為用戶級線程與內核之間的接口。
- 內核控制線程 這種線程又稱為輕型進程LWP(Light Weight Process)。 每一個進程都可擁有多個LWP, 同用戶級線程一樣, 每個LWP都有自己的數據結構(如TCB),其中包括線程標識符、優先級、 狀態, 另外還有棧和局部存儲區等。 它們也可以共享進程所擁有的資源。LWP可通過系統調用來獲得內核提供的服務,這樣,當一個用戶級線程運行時,只要將它連接到一個LWP上,此時它便具有了內核支持線程的所有屬性。?