進程通信的目的
-
數據傳輸
一個進程需要將它的數據發送給另一個進程,發送的數據量在一個字節到幾M字節之間 -
共享數據
多個進程想要操作共享數據,一個進程對共享數據 -
通知事
一個進程需要向另一個或一組進程發送消息,通知它(它們)發生了某種事件(如進程終止時要通知父進程)。 -
資源共享
多個進程之間共享同樣的資源。爲了作到這一點,需要內核提供鎖和同步機制。 -
進程控制
有些進程希望完全控制另一個進程的執行(如Debug進程),此時控制進程希望能夠攔截另一個進程的所有陷入和異常,並能夠及時知道它的狀態改變。
Linux 進程間通信(IPC)的發展
Linux下的進程通信手段基本上是從Unix平臺上的進程通信手段繼承而來的。而對Unix發展做出重大貢獻的兩大主力AT&T的貝爾實驗室及BSD(加州大學伯克利分校的伯克利軟件發佈中心)在進程間通信方面的側重點有所不同。
前者對Unix早期的進程間通信手段進行了系統的改進和擴充,形成了“system V IPC”,通信進程侷限在單個計算機內;
後者則跳過了該限制,形成了基於套接口(socket)的進程間通信機制。
linux則把兩者繼承了下來
-
早期UNIX進程間通信
-
基於System V進程間通信
-
基於Socket進程間通信
-
POSIX進程間通信。
UNIX進程間通信方式包括:管道、FIFO、信號。
System V進程間通信方式包括:System V消息隊列、System V信號燈、System V共享內存
POSIX進程間通信包括:posix消息隊列、posix信號燈、posix共享內存。
linux使用的進程間通信方式
-
管道(pipe),流管道(s_pipe)和有名管道(FIFO)
-
信號(signal)
-
消息隊列
-
共享內存
-
信號量
-
套接字(socket)
管道( pipe )
管道這種通訊方式有兩種限制,一是半雙工的通信,數據只能單向流動,二是只能在具有親緣關係的進程間使用。進程的親緣關係通常是指父子進程關係。
流管道s_pipe: 去除了第一種限制,可以雙向傳輸.
管道可用於具有親緣關係進程間的通信,命名管道:name_pipe克服了管道沒有名字的限制,因此,除具有管道所具有的功能外,它還允許無親緣關係進程間的通信;
信號量( semophore )
信號量是一個計數器,可以用來控制多個進程對共享資源的訪問。它常作爲一種鎖機制,防止某進程正在訪問共享資源時,其他進程也訪問該資源。因此,主要作爲進程間以及同一進程內不同線程之間的同步手段。
信號是比較複雜的通信方式,用於通知接受進程有某種事件發生,除了用於進程間通信外,進程還可以發送信號給進程本身;linux除了支持Unix早期信號語義函數sigal外,還支持語義符合Posix.1標準的信號函數sigaction(實際上,該函數是基於BSD的,BSD爲了實現可靠信號機制,又能夠統一對外接口,用sigaction函數重新實現了signal函數);
消息隊列( message queue )
消息隊列是由消息的鏈表,存放在內核中並由消息隊列標識符標識。消息隊列克服了信號傳遞信息少、管道只能承載無格式字節流以及緩衝區大小受限等缺點。
消息隊列是消息的鏈接表,包括Posix消息隊列system V消息隊列。有足夠權限的進程可以向隊列中添加消息,被賦予讀權限的進程則可以讀走隊列中的消息。消息隊列克服了信號承載信息量少,管道只能承載無格式字節流以及緩衝區大小受限等缺點。
信號 ( singal )
信號是一種比較複雜的通信方式,用於通知接收進程某個事件已經發生。
主要作爲進程間以及同一進程不同線程之間的同步手段。
共享內存( shared memory )
共享內存就是映射一段能被其他進程所訪問的內存,這段共享內存由一個進程創建,但多個進程都可以訪問。共享內存是最快的 IPC 方式,它是針對其他進程間通信方式運行效率低而專門設計的。它往往與其他通信機制,如信號量,配合使用,來實現進程間的同步和通信。
使得多個進程可以訪問同一塊內存空間,是最快的可用IPC形式。是針對其他通信機制運行效率較低而設計的。往往與其它通信機制,如信號量結合使用,來達到進程間的同步及互斥。
套接字( socket )
套解口也是一種進程間通信機制,與其他通信機制不同的是,它可用於不同機器間的進程通信
更爲一般的進程間通信機制,可用於不同機器之間的進程間通信。起初是由Unix系統的BSD分支開發出來的,但現在一般可以移植到其它類Unix系統上:Linux和System V的變種都支持套接字。
進程間通信各種方式效率比較
類型 | 無連接 | 可靠 | 流控制 | 記錄消息類型 | 優先級 |
---|---|---|---|---|---|
普通PIPE | N | Y | Y | N | |
流PIPE | N | Y | Y | N | |
命名PIPE(FIFO) | N | Y | Y | N | |
消息隊列 | N | Y | Y | Y | |
信號量 | N | Y | Y | Y | |
共享存儲 | N | Y | Y | Y | |
UNIX流SOCKET | N | Y | Y | N | |
UNIX數據包SOCKET | Y | Y | N | N |
注:無連接: 指無需調用某種形式的OPEN,就有發送消息的能力流控制:
如果系統資源短缺或者不能接收更多消息,則發送進程能進行流量控制
各種通信方式的比較和優缺點
-
管道:速度慢,容量有限,只有父子進程能通訊
-
FIFO:任何進程間都能通訊,但速度慢
-
消息隊列:容量受到系統限制,且要注意第一次讀的時候,要考慮上一次沒有讀完數據的問題
-
信號量:不能傳遞複雜消息,只能用來同步
-
共享內存區:能夠很容易控制容量,速度快,但要保持同步,比如一個進程在寫的時候,另一個進程要注意讀寫的問題,相當於線程中的線程安全,當然,共享內存區同樣可以用作線程間通訊,不過沒這個必要,線程間本來就已經共享了同一進程內的一塊內存
如果用戶傳遞的信息較少或是需要通過信號來觸發某些行爲.前文提到的軟中斷信號機制不失爲一種簡捷有效的進程間通信方式.
但若是進程間要求傳遞的信息量比較大或者進程間存在交換數據的要求,那就需要考慮別的通信方式了。
無名管道簡單方便.但侷限於單向通信的工作方式.並且只能在創建它的進程及其子孫進程之間實現管道的共享:
有名管道雖然可以提供給任意關係的進程使用.但是由於其長期存在於系統之中,使用不當容易出錯.所以普通用戶一般不建議使用。
消息緩衝可以不再侷限於父子進程,而允許任意進程通過共享消息隊列來實現進程間通信,並由系統調用函數來實現消息發送和接收之間的同步,從而使得用戶在使用消息緩衝進行通信時不再需要考慮同步問題,使用方便,但是信息的複製需要額外消耗CPU的時間,不適宜於信息量大或操作頻繁的場合。
共享內存針對消息緩衝的缺點改而利用內存緩衝區直接交換信息,無須複製,快捷、信息量大是其優點。
但是共享內存的通信方式是通過將共享的內存緩衝區直接附加到進程的虛擬地址空間中來實現的,因此,這些進程之間的讀寫操作的同步問題操作系統無法實現。必須由各進程利用其他同步工具解決。另外,由於內存實體存在於計算機系統中,所以只能由處於同一個計算機系統中的諸進程共享。不方便網絡通信。
共享內存塊提供了在任意數量的進程之間進行高效雙向通信的機制。每個使用者都可以讀取寫入數據,但是所有程序之間必須達成並遵守一定的協議,以防止諸如在讀取信息之前覆寫內存空間等競爭狀態的出現。
不幸的是,Linux無法嚴格保證提供對共享內存塊的獨佔訪問,甚至是在您通過使用IPC_PRIVATE創建新的共享內存塊的時候也不能保證訪問的獨佔性。 同時,多個使用共享內存塊的進程之間必須協調使用同一個鍵值。