2013-08-10 15:45:31算法
這兩天看進程的同步與通訊,看了幾本書上的介紹,也從網上搜了不少資料,越看越迷惑,被這幾個問題搞得很糾結。數據庫
在好多教材上(包括國內與國外的)也沒有明確這些概念,如今對每一個問題尚未準確的答案,下面將本身的理解記下來,之後再補充。編程
參考資料:安全
《操做系統教程》 孫鍾秀主編 費翔林 駱斌 謝立參編 高等教育出版社網絡
《計算機操做系統》 何炎祥 李飛 李寧 編著 清華大學出版社(進程管理部分與《操做系統教程》中的相似)多線程
進程互斥、同步的概念是併發進程下存在的概念,有了併發進程,就產生了資源的競爭與協做,從而就要經過進程的互斥、同步、通訊來解決資源的競爭與協做問題。併發
下面是根據《操做系統教程》3.1.4 中的介紹,整理的進程互斥、同步的概念。socket
在多道程序設計系統中,同一時刻可能有許多進程,這些進程之間存在兩種基本關係:競爭關係和協做關係。分佈式
進程的互斥、同步、通訊都是基於這兩種基本關係而存在的,爲了解決進程間競爭關係(間接制約關係)而引入進程互斥;爲了解決進程間鬆散的協做關係( 直接制約關係)而引入進程同步;爲了解決進程間緊密的協做關係而引入進程通訊。模塊化
第一種是競爭關係
系統中的多個進程之間彼此無關,它們並不知道其餘進程的存在,而且也不受其餘進程執行的影響。例如,批處理系統中創建的多個用戶進程, 分時系統中創建的多個終端進程。因爲這些進程共用了一套計算機系統資源,於是, 必然要出現多個進程競爭資源的問題。當多個進程競爭共享硬設備、存儲器、處理器 和文件等資源時,操做系統必須協調好進程對資源的爭用。
資源競爭出現了兩個控制問題:一個是死鎖 (deadlock )問題,一組進程若是都得到了部分資源,還想要獲得其餘進程所佔有的資源,最終全部的進程將陷入死鎖。另外一個是飢餓(starvation )問題,這是指這樣一種狀況:一個進程因爲其餘進程老是優先於它而被無限期拖延。
操做系統須要保證諸進程能互斥地訪問臨界資源,既要解決飢餓問題,又要解決死鎖問題。
進程的互斥(mutual exclusion )是解決進程間競爭關係( 間接制約關係) 的手段。 進程互斥指若干個進程要使用同一共享資源時,任什麼時候刻最多容許一個進程去使用,其餘要使用該資源的進程必須等待,直到佔有資源的進程釋放該資源。
第二種是協做關係
某些進程爲完成同一任務須要分工協做,因爲合做的每個進程都是獨立地以不可預知的速度推動,這就須要相互協做的進程在某些協調點上協 調各自的工做。當合做進程中的一個到達協調點後,在還沒有獲得其夥伴進程發來的消息或信號以前應阻塞本身,直到其餘合做進程發來協調信號或消息後方被喚醒並繼續執行。這種協做進程之間相互等待對方消息或信號的協調關係稱爲進程同步。
進程間的協做能夠是雙方不知道對方名字的間接協做,例如,經過共享訪問一個緩衝區進行鬆散式協做;也能夠是雙方知道對方名字,直接經過通訊機制進行緊密協做。容許進程協同工做有利於共享信息、有利於加快計算速度、有利於實現模塊化程序設計。
進程的同步(Synchronization)是解決進程間協做關係( 直接制約關係) 的手段。進程同步指兩個以上進程基於某個條件來協調它們的活動。一個進程的執行依賴於另外一
個協做進程的消息或信號,當一個進程沒有獲得來自於另外一個進程的消息或信號時則需等待,直到消息或信號到達才被喚醒。
不難看出,進程互斥關係是一種特殊的進程同步關係,即逐次使用互斥共享資源,也是對進程使用資源次序上的一種協調。
下面是根據《操做系統教程》3.5 中的介紹,整理的進程通訊的概念。
併發進程之間的交互必須知足兩個基本要求:同步和通訊。
進程競爭資源時要實施互斥,互斥是一種特殊的同步,實質上須要解決好進程同步問題,進程同步是一種進程通訊,經過修改信號量,進程之間可創建起聯繫,相互協調運行和協同工做。可是信號量與PV操做只能傳遞信號,沒有傳遞數據的能力。有些狀況下進程之間交換的信息量雖不多,例如,僅僅交換某個狀態信息,但不少狀況下進程之間須要交換大批數據,例如,傳送一批信息或整個文件,這能夠經過一種新的通訊機制來完成,進程之間互相交換信息的工做稱之爲進程通訊IPC (InterProcess Communication)(主要是指大量數據的交換)。進程間通訊的方式不少,包括:
前面提到,進程互斥關係是一種特殊的進程同步關係,下面給出常見的進程同步的方法,實際上也可用於進程的互斥(我的理解)。
在何炎祥的《計算機操做系統》 3.2 節,將進程同步的機制與解決進程互斥方法看作是同樣的,的明確指出互斥的軟件解決方法爲Dekker算法與Peterson算法,互斥的硬件解決方法爲中斷方法、以及使用機器指令的方法,後面又給出了信號量、管程、消息傳遞三種方法。
實際應用中,不一樣的系統有不一樣的進程同步方法,CSDN帖子http://bbs.csdn.net/topics/80156687中有一些討論,Linux 與Windows的主要同步、通訊機制以下:
Linux 下:
Linux 下常見的進程同步方法有:SysVIPC 的 sem(信號量)、file locking / record locking(經過 fcntl 設定的文件鎖、記錄鎖)、futex(基於共享內存的快速用戶態互斥鎖)。針對線程(pthread)的還有 pthread_mutex 和 pthread_cond(條件變量)。
Linux 下常見的進程通訊的方法有 :pipe(管道),FIFO(命名管道),socket(套接字),SysVIPC 的 shm(共享內存)、msg queue(消息隊列),mmap(文件映射)。之前還有 STREAM,不過如今比較少見了(好像)。
Windows下:
在Windwos中,進程同步主要有如下幾種:互斥量、信號量、事件、可等計時器等幾種技術。
在Windows下,進程通訊主要有如下幾種:內存映射、管道、消息等,可是內存映射是最基礎的,由於,其餘的進程通訊手段在內部都是考內存映射來完成的。
對於該問題,教材上沒有明確的回答,教材上給出的通常是進程而非線程的同步、通訊方式。但網絡上不少說法將二者混爲一談。根據教材,以及網上的說法,我的的理解爲:
同步機制:
信號量、管程、互斥是進程的同步機制,而信號量、互斥也可用於線程的同步,但管程只在進程同步中被用到;
線程的同步除了信號量、互斥外,還有臨界區、事件,沒有看到教材上將這兩種方式做爲進程的同步方式;
通訊機制:
管道、FIFO、消息隊列、信號量、共享內存是進程的同步機制,教材上沒有線程的通訊機制這樣的說法,但能夠確定這幾種方法是進程的通訊方式,且其中的信號量既可用於進程的同步,又可用於進程的通訊,在網絡上還有說能夠用於線程同步的。
管道與管程是不一樣的,管程是進程同步的方式,而管道則是進程通訊的方式。
下面是常見的線程之間的同步方式的詳細介紹。
(注:下面轉自網絡,下面的同步、通訊方式對於進程與線程分的不是很清楚,關於進程仍是線程的解釋見上面——線程的同步/通訊與進程的同步/通訊有區別嗎?)
1、進程/線程間同步機制。
臨界區、互斥區、事件、信號量四種方式
臨界區(Critical Section)、互斥量(Mutex)、信號量(Semaphore)、事件(Event)的區別
一、臨界區:經過對多線程的串行化來訪問公共資源或一段代碼,速度快,適合控制數據訪問。
在任意時刻只容許一個線程對共享資源進行訪問,若是有多個線程試圖訪問公共資源,那麼在有一個線程進入後,其餘試圖訪問公共資源的線程將被掛起,並一直等到進入臨界區的線程離開,臨界區在被釋放後,其餘線程才能夠搶佔。
二、互斥量:採用互斥對象機制。
只有擁有互斥對象的線程纔有訪問公共資源的權限,由於互斥對象只有一個,因此能保證公共資源不會同時被多個線程訪問。互斥不只能實現同一應用程序的公共資源安全共享,還能實現不一樣應用程序的公共資源安全共享 .互斥量比臨界區複雜。由於使用互斥不只僅可以在同一應用程序不一樣線程中實現資源的安全共享,並且能夠在不一樣應用程序的線程之間實現對資源的安全共享。
三、信號量:它容許多個線程在同一時刻訪問同一資源,可是須要限制在同一時刻訪問此資源的最大線程數目 .
信號量對象對線程的同步方式與前面幾種方法不一樣,信號容許多個線程同時使用共享資源,這與操做系統中的PV操做相同。它指出了同時訪問共享資源的線程最大數目。它容許多個線程在同一時刻訪問同一資源,可是須要限制在同一時刻訪問此資源的最大線程數目。
PV操做及信號量的概念都是由荷蘭科學家E.W.Dijkstra提出的。信號量S是一個整數,S大於等於零時表明可供併發進程使用的資源實體數,但S小於零時則表示正在等待使用共享資源的進程數。
P操做申請資源:
(1)S減1;
(2)若S減1後仍大於等於零,則進程繼續執行;
(3)若S減1後小於零,則該進程被阻塞後進入與該信號相對應的隊列中,而後轉入進程調度。
V操做 釋放資源:
(1)S加1;
(2)若相加結果大於零,則進程繼續執行;
(3)若相加結果小於等於零,則從該信號的等待隊列中喚醒一個等待進程,而後再返回原進程繼續執行或轉入進程調度。
四、事 件: 經過通知操做的方式來保持線程的同步,還能夠方便實現對多個線程的優先級比較的操做 .
總結:
1. 互斥量與臨界區的做用很是類似,但互斥量是能夠命名的,也就是說它能夠跨越進程使用。因此建立互斥量須要的資源更多,因此若是隻爲了在進程內部是用的話使用臨界區會帶來速度上的優點並可以減小資源佔用量。由於互斥量是跨進程的互斥量一旦被建立,就能夠經過名字打開它。
2. 互斥量(Mutex),信號燈(Semaphore),事件(Event)均可以被跨越進程使用來進行同步數據操做,而其餘的對象與數據同步操做無關,但對於進程和線程來說,若是進程和線程在運行狀態則爲無信號狀態,在退出後爲有信號狀態。因此可使用WaitForSingleObject來等待進程和線程退出。
3. 經過互斥量能夠指定資源被獨佔的方式使用,但若是有下面一種狀況經過互斥量就沒法處理,好比如今一位用戶購買了一份三個併發訪問許可的數據庫系統,能夠根據用戶購買的訪問許可數量來決定有多少個線程/進程能同時進行數據庫操做,這時候若是利用互斥量就沒有辦法完成這個要求,信號燈對象能夠說是一種資源計數器。
2、進程間通訊方式
因爲比較容易混淆,咱們把進程間通訊方法也列在這裏作比較。
進程通訊也就是所謂的IPC問題,主要是指進程間交換數據的方式。進程通訊包括高級通訊與低級通訊,其中進程同步與互斥屬於低級通訊,主要用於插U農地控制信號;高級通訊包括三種:共享存儲系統(有的地方稱做共享內存區)、消息傳遞系統(有的地方稱做消息隊列)、管道。
信號量是進程同步與互斥的經常使用方法,也能夠做爲低級的進程通訊方法,用於傳遞控制信號。
簡而言之,進程間通訊方式主要包括管道、FIFO、消息隊列、信號量、共享內存。
1.管道,還有命名管道和非命名管道(即匿名管道)之分,非命名管道(即匿名管道)只能用於父子進程通信,命名管道可用於非父子進程,命名管道就是FIFO,管道是先進先出的通信方式
2.消息隊列,是用於兩個進程之間的通信,首先在一個進程中建立一個消息隊列,而後再往消息隊列中寫數據,而另外一個進程則從那個消息隊列中取數據。須要注意的是,消息隊列是用建立文件的方式創建的,若是一個進程向某個消息隊列中寫入了數據以後,另外一個進程並無取出數據,即便向消息隊列中寫數據的進程已經結束,保存在消息隊列中的數據並無消失,也就是說下次再從這個消息隊列讀數據的時候,就是上次的數據!!!!
3.信號量,它與WINDOWS下的信號量是同樣的,因此就不用多說了
4.共享內存,相似於WINDOWS下的DLL中的共享變量,但LINUX下的共享內存區不須要像DLL這樣的東西,只要首先建立一個共享內存區,其它進程按照必定的步驟就能訪問到這個共享內存區中的數據,固然可讀可寫
以上幾種方式的比較:
1.管道:速度慢,容量有限,只有父子進程能通信
2.FIFO:任何進程間都能通信,但速度慢
3.消息隊列:容量受到系統限制,且要注意第一次讀的時候,要考慮上一次沒有讀完數據的問題
4.信號量:不能傳遞複雜消息,只能用來同步
5.共享內存區:可以很容易控制容量,速度快,但要保持同步,好比一個進程在寫的時候,另外一個進程要注意讀寫的問題,至關於線程中的線程安全,固然,共享內存區一樣能夠用做線程間通信,不過沒這個必要,線程間原本就已經共享了同一進程內的一塊內存
本質上,信號量是一個計數器,它用來記錄對某個資源(如共享內存)的存取情況。通常說來,爲了得到共享資源,進程須要執行下列操做:
3、進程/線程同步機制與進程間通訊機制比較
很明顯2者有相似,可是差異很大
同步主要是臨界區、互斥、信號量、事件
進程間通訊是管道、內存共享、消息隊列、信號量、socket
共通之處是,信號量和消息(事件)
信號量是進程同步與互斥的經常使用方法,也能夠做爲低級的進程通訊方法,用於傳遞控制信號;
管道與管程是不一樣的,管程是進程同步的方式,而管道則是進程通訊的方式;