進程的前三個部分(進程的基本概念、進程控制、線程)請閱讀 操做系統-4-進程管理(一)html
4、進程同步程序員
概念:進程同步的主要任務是使併發執行的各進程之間能有效的共享資源和相互合做,從而使程序的執行具備可再現性。
1 進程同步的基本概念算法
(1)進程之間的兩種制約關係:間接制約關係:系統資源競爭,進程間彼此無關
直接制約關係:進程間合做,彼此相關
(2)資源競爭需解決的兩個問題:死鎖(Deadlock)問題、飢餓(Starvation)問題(既要解決飢餓問題,又要解決死鎖問題。)數組
(3)進程互斥:概念:進程互斥指若干進程要使用同一共享資源時,任什麼時候刻最多容許一個進程使用,其餘進程必須等待,直到佔有資源的進程釋放該資源。
做用:進程互斥是解決進程間競爭關係(間接制約關係)的手段。服務器
(4)進程合做:概念:進程合做是指某些進程爲完成同一任務須要分工協做。
做用:進程合做是解決進程間協做關係(直接制約關係)的手段。網絡
(5)進程合做與進程互斥的區別:進程同步指兩個以上進程基於某個條件來協調它們的活動。一個進程的執行依賴於協做進程的消息或信號,數據結構
當一個進程沒有獲得來自於協做進程的消息或信號時需等待,直到消息或信號到達才被喚醒。併發
進程互斥是一種特殊的進程同步關係,即依次使用互斥共享資源,是對進程使用資源次序上的一種協調。函數
(6)臨界資源(Critical Resource/CR):一次僅容許一個進程訪問的資源。如:進程P一、P2共享一臺打印機,若讓它們交替使用則獲得的結果確定是不可理解的。
臨界資源多是硬件,也多是軟件:變量,數據,表格,隊列等。
併發進程對臨界資源的訪問必須做某種限制,不然就可能出現與時間有關的錯誤,如:聯網售票。工具
(7)臨界區(Critical Section/CS): 臨界段,在每一個程序中,訪問臨界資源的那段程序。
與同一變量有關的臨界區分散在各進程的程序段中,而各進程的執行速度不可預知。
若是能保證進程在臨界區執行時,不讓另外一個進程進入臨界區,即各進程對共享變量的訪問是互斥的,就不會形成與時間有關的錯誤。
與時間有關的錯誤: 一飛機訂票系統,兩個終端,運行T一、T2進程
T1 : T2:
... ...
Read(x); Read(x);
if x>=1 then if x>=1 then
x:=x-1; x:=x-1;
write(x); write(x);
... ...
注意:臨界區是對某一臨界資源而言的,對於不一樣臨界資源的臨界區,它們之間不存在互斥。
如程序段A、B有關於變量X的臨界區,而C、D有關於變量Y的臨界區,
那麼,A、B之間須要互斥執行,C、D之間也要互斥執行,而A與C、B與D之間不用互斥執行。
臨界區的調度原則:一次至多容許一個進程進入臨界區內
一個進程不能無限地停留在臨界區內
一個進程不能無限地等待進入臨界區
(8)同步機制應遵循的規則:空閒讓進、忙則等待、有限等待、讓權等待
用軟件方法解決進程互斥問題:(設兩個進程Pi、Pj使用臨界資源。)
算法一分析:該算法規定了進程必須輪流執行;若某進程不須要進入CS,而另外一進程要求連續進入CS,該算法不能解決;破壞了「空閒讓進」的準則;
算法二分析:該算法解決了算法一「空閒讓進」的問題;
該算法中,若多個進程同時要求進入CS時,都發現對方進程的標誌爲「假」,會同時進入CS,這樣,破壞了「忙則等待」的準則;
算法三分析:該算法解決了算法二「忙則等待」的問題;
該算法中,若多個進程同時要求進入CS時,都將本身的標誌設爲「真」,這樣,互相謙讓,誰也不會進入CS。這樣,破壞了「空閒讓進」的準則;
算法四分析:知足空閒讓進、忙則等待、有限等待、讓權等待四個規則
生產者消費者問題:
問題分析:利用一個數組表示具備n個緩衝區的循環緩衝池;
用輸入指針in指示下一個可投放產品的緩衝區,每當生產者進程生產並投放一個產品,輸入指針加1 (in:=(in+1) mod n);
用指針out指示下一個可從中獲取產品的緩衝區,每當消費者進程取出一個產品,輸出指針加1 (out:=(out+1) mod n) ;
----------------------------------------------------------------------------------------------------------------
2 信號量機制
概念:1965年,由荷蘭學者Dijkstra提出,P、V操做分別是荷蘭語的test (Proberen) 和increment (Verhogen) 。
信號量機制是一種卓有成效的進程同步機制。經歷整型信號量、記錄型信號量,發展爲「信號量集」機制。
P、V操做是原語。
信號量的值除初始化外,只能由P、V原語修改。(wait、signal)
型號量的分類:信號量按其用途分爲:公用信號量、私有信號量
信號量按其取值分爲:二元信號量、通常信號量
(1)整型信號量:定義爲一個整型量,由兩個標準原子操做wait(S)(P操做)和signal(S)(V操做)來訪問。
P(S) 或 wait(S): while S≤0 do no-op;
S:=S-1;
V(S) 或 signal(S): S:=S+1;
整型信號量出現「忙等」現象。
P(S) 或 wait(S): S:=S-1; S>0:可用資源數量
if (S<0) block(); S<0:|S|表示等待使用資源的進程數量
V(S) 或 signal(S): S:=S+1;
if (S<=0) wakeup();
利用整型信號量實現互斥:
(2)記錄型信號量:記錄型信號量機制採起「讓權等待」策略,即當進程不能申請到資源時,讓出CPU使用權。避免了整型信號量出現的「忙等」現象。
記錄型信號量須要一個用於表明資源數目的整型變量value,一個用於連接全部等待進程的進程鏈表queue。
數據結構定義以下: struct semaphore {
int value;
pointer_PCB queue;
};
信號量說明:struct semaphore s;
P操做:P(s){
s.value = s.value -1 ;
if (s.value < 0){
該進程狀態置爲等待狀態
將該進程的PCB插入相應的等待隊列末尾s.queue;
}
}
V操做:V(s){
s.value = s.value +1 ;
if (s.value <= 0){
喚醒相應等待隊列s.queue中等待的一個進程
改變其狀態爲就緒狀態,並將其插入就緒隊列
}
}
進程對CR進行申請:begin
repeat
P(S);
CS;
V(S);
remainder;
until false;
end
(3)AND型信號量
AND信號量是針對進程間共享多個資源;
例如:兩個進程A、B要求訪問共享數據D、E。爲D、E分別設置用於互斥的信號量Dmutex、Emutex,初值爲1。
process A: process B:
wait(Dmutex); wait(Emutex);
wait(Emutex); wait(Dmutex);
此處出現死等現象
AND同步機制的基本思想是:將進程在整個運行過程當中須要的全部資源,一次性所有地分配給進程,待進程使用完後再一塊兒釋放。
只要尚有一個資源未分配給進程,其它全部可能爲之分配的資源,也不分配。
實現時在wait操做中,增長一個「AND」條件,故稱爲AND同步,或同時wait操做(Swait)。
-------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------
(4)信號量集
進程對信號量Si的測試值爲ti(表示信號量的判斷條件,要求Si >= ti;即當資源數量低於ti時,便不予分配)
佔用值爲di(表示資源的申請量,即Si=Si-di)
對應的P、V原語格式爲:
Swait(S1, t1, d1; ...; Sn, tn, dn);
Ssignal(S1, d1; ...; Sn, dn);
通常「信號量集」能夠用於各類狀況的資源分配和釋放,幾種特殊狀況:
(1)Swait(S, d, d)表示每次申請d個資源,當少於d個時,便不分配
(2)Swait(S, 1, 1)表示記錄型信號量或互斥信號量
(3)Swait(S, 1, 0)可做爲一個可控開關(當S1時,容許多個進程進入特定區域;當S=0時,禁止任何進程進入該特定區域)
(4)通常「信號量集」未必成對使用。如:一塊兒申請,但不一塊兒釋放!
5、經典的進程同步問題(等我後續單獨寫博客)
1 生產者/消費者問題
2 讀者/寫者問題
3 哲學家進餐問題
6、管程機制
引入管程機制的緣由:減小大量的同步操做分散在各個進程中。
解決的辦法——引入管程:爲每一個可共享資源設立一個專門的管程,來統一管理各進程對該資源的訪問。
管程(Monitor)的定義:一個管程包含一個數據結構和能爲併發進程所執行(在該數據結構上)的一組操做,這組操做能同步進程和改變管程中的數據。
管程的三個部分:侷限於管程內使用的共享變量的定義
對侷限於管程的數據初始化
對該數據結構進行操做的一組過程
管程的特色:(1)局部數據變量只能被管程的過程訪問,任何外部過程都不能訪問。
(2)一個進程經過調用管程的一個過程進入管程。
(3)任什麼時候候,只能有一個進程在管程中執行,調用管程的任何其餘進程都被掛起,以等待管程變成可用的。(由編譯器控制一次只能有一個進程調用管程)
(4)爲了保證共享變量的數據一致性,管程應互斥使用。
(5)管程一般是用於管理資源的,所以管程中有進程等待隊列和相應的等待和喚醒操做。
(6)在管程入口有一個等待隊列,稱爲入口等待隊列。當一個已進入管程的進程等待時,就釋放管程的互斥使用權;
當已進入管程的一個進程喚醒另外一個進程時,二者必須有一個退出或中止使用管程。
(7)在管程內部,因爲執行喚醒操做,可能存在多個等待進程(等待使用管程),稱爲緊急等待隊列,它的優先級高於入口等待隊列。
描述:一個進程進入管程以前要先申請,通常由管程提供一個enter()過程;
離開時釋放使用權,若是緊急等待隊列不空,則喚醒第一個等待者,通常也由管程提供外部過程leave()。
管程內部有本身的等待機制。管程能夠說明一種特殊的條件型變量:var c:condition;其實是一個指針,指向一個等待該條件的PCB隊列。
條件變量其實是區分阻塞的緣由。
條件變量:管程利用wait原語讓進程等待,等待的緣由可用條件變量condition區別。它們應置於wait和signal以前。
例如:var X:condition;X.signal表示從新啓動一個被阻塞的進程,但若是沒有被阻塞的進程,則X.signal不產生任何後果。
利用管程解決生產者-消費者問題(待我後續發佈博客)
7、進程通訊
1 概念
(1)所謂進程通訊是指進程之間信息交換。
(2)P、V操做實現的是進程之間的低級通訊,因此P、V爲低級通訊原語。它只能傳遞簡單的信號,不能傳遞交換大量信息。
(3)若要在進程間傳遞大量信息能夠用Send、 Receive原語(高級通訊原語)。
(4)信號量機制做爲同步工具成效顯著,但做爲通訊工具,存在不足:
效率低。生產者一次只能放一個產品(消息)到緩衝區,消費者一次只能取一個產品(消息);
通訊對用戶不透明。
用戶用低級通訊工具不夠方便,由於數據結構設置、傳送、進程互斥、同步等都由程序員負責。
2 進程通訊類型
高級通訊:用戶可直接利用OS提供的一組通訊命令高效傳送大量數據。分爲:
(1)共享存儲器系統(Shared-Memory System) :進程間經過共享某些數據結構或共享存儲區進行通訊。
基於共享數據結構的通訊方式:多個進程經過公用某些數據結構交換信息。如:生產者-消費者問題中的有界緩衝區。
該方式低效。因數據結構設置、同步等由程序員負責。
基於共享存儲區的通訊方式:高級通訊,在存儲器中劃出一塊共享存儲區,進程在通訊前,向系統申請共享存儲區中的一個分區,
並指定該分區的關鍵字,若系統已經給其它進程分配了這樣的分區,則將該分區的描述符返回給申請者。
接着,申請者把得到的共享存儲分區鏈接到本進程上,此後可讀寫該分區。
注:以上兩種方式的同步互斥都要由進程本身負責。
(2)消息傳遞系統(Message Passing System):進程間的數據交換以格式化的消息爲單位,程序員利用系統的通訊原語實現通訊。 如:網絡中的報文。
操做系統隱藏了通訊的實現細節,簡化了通訊程序編制的複雜性,於是獲得普遍應用。
消息傳遞系統可分爲:
直接通訊(也稱爲消息緩衝通訊):發送進程直接把消息發送給接收者,並將它掛在接收進程的消息緩衝隊列上。接收進程從消息緩衝隊列中取得消息。
間接通訊:發送進程將消息發送到某種中間實體中(信箱),接收進程從(信箱)中取得消息。也稱信箱通訊。在網絡中稱爲電子郵件系統。
兩種通訊方式的主要區別:前者須要兩進程都存在,後者不須要。
(3)管道(Pipe)通訊 (共享文件方式):管道是最初的UNIX IPC形式,它能傳送大量數據,被普遍採用。
所謂管道,是指用於鏈接一個讀進程和一個寫進程的文件,稱pipe文件。
向管道提供輸入的進程(稱寫進程),以字符流的形式將大量數據送入管道,而接受管道輸出的進程(讀進程)可從管道中接收數據。
管道能夠是單工的,也能夠是雙工的。
管道分類:無名管道只限於相同祖先的進程間使用,是單向的。好比:父進程與子進程之間,或同一父進程的兩個子進程間。
有名管道可在任意兩個進程間使用,有名文件,有函數建立,而且建立進程即便終止了,該管道仍存在,是單向的,半雙工的。
管道與消息隊列的區別:管道中的消息是無界的
管道是外存的,消息隊列是內存的
管道機制必須提供如下三方面能力:
互斥:一個進程讀/寫管道時,另外一個讀/寫進程必須等待。
同步:寫進程寫入後,只有等到讀進程讀走數據後,才能再寫;一樣,讀進程無數據讀時,只有等到寫進程寫入後,被喚醒再讀。
肯定對方是否存在:只有對方存在時才能通訊。
3 消息傳遞通訊的實現方法
消息通訊分爲直接通訊和間接通訊。
直接通訊方式:通訊命令(原語):Send(Receiver,message);
Receive(Sender,message);
間接通訊方式(信箱方式):信箱的建立與撤消。建立者應給出信箱名、屬性(公用、私用或共享)等
信箱中消息的發送與接收:Send(mailbox,message);
Receive(mailbox,message);
信箱的種類(3類)
私用信箱:用戶進程爲本身建立的信箱,是進程的一部分。只有本身有權讀,其餘進程只能向信箱發消息;可採用單向鏈路實現。
公用信箱:由操做系統建立,全部系統覈准進程均可使用;採用雙向通訊鏈路實現。
共享信箱:由某進程建立並指明可共享,則擁有者和共享者可以使用。
利用信箱通訊時,有四種關係:1:1 發送和接收進程之間創建專用鏈路;
N:1 即客戶/服務器;
1:N 發送進程可用廣播方式向多個接收者發消息;
N:N 創建一個公共信箱,多個進程都能向信箱中發消 息,也能從信箱中取消息;
信箱使用規則:若發送信件時信箱已滿,則發送進程被置爲「等信箱」狀態,直到信箱有空時才被喚醒
若取信件時信箱中無信,則接收進程被置爲「等信件」狀態,直到有信件時才被喚醒
Send實現:send(MailBox,M):把信件M送到指定的信箱MailBox中
步驟:查找指定信箱MailBox ;
若信箱未滿,則把信件M送入信箱且喚醒「等信件」者;
若信箱已滿,置發送信件進程爲「等信箱」狀態;
Receive實現:receive(MailBox,X):從指定信箱MailBox中取出一封信,存放到指定的地址X中 步驟:查找指定信箱MailBox ; 若信箱中有信,則取出一封信存於X中且喚醒「等信箱」者; 若信箱中無信件,置接收信件進程「等信件」狀態;