Linux進程間通信的幾種方式總結--linux內核剖析(七)
進程間通信概述
進程通信的目的
傳輸數據
一個進程須要將它的數據發送給還有一個進程。發送的數據量在一個字節到幾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共享內存。
因為Unix版本號的多樣性,電子電氣project協會(IEEE)開發了一個獨立的Unix標準,這個新的ANSI Unix標準被稱為計算機環境的可移植性操作系統界面(PSOIX)。
現有大部分Unix和流行版本號都是遵循POSIX標準的。而Linux從一開始就遵循POSIX標準;
BSD並非沒有涉足單機內的進程間通信(socket本身就能夠用於單機內的進程間通信)。
其實,非常多Unix版本號的單機IPC留有BSD的痕跡。如4.4BSD支持的匿名內存映射、4.3+BSD對可靠信號語義的實現等等。
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:不論什麽進程間都能通訊,但速度慢
消息隊列:容量受到系統限制,且要註意第一次讀的時候,要考慮上一次沒有讀完數據的問題
信號量:不能傳遞復雜消息,僅僅能用來同步
共享內存區:能夠非常easy控制容量,速度快,但要保持同步,比方一個進程在寫的時候。還有一個進程要註意讀寫的問題,相當於線程中的線程安全。當然。共享內存區相同能夠用作線程間通訊,只是沒這個必要,線程間本來就已經共享了同一進程內的一塊內存
假設用戶傳遞的信息較少或是須要通過信號來觸發某些行為.前文提到的軟中斷信號機制不失為一種簡捷有效的進程間通信方式.
但若是進程間要求傳遞的信息量比較大或者進程間存在交換數據的要求,那就須要考慮別的通信方式了。
無名管道簡單方便.但局限於單向通信的工作方式.而且僅僅能在創建它的進程及其子孫進程之間實現管道的共享:
有名管道盡管能夠提供給隨意關系的進程使用.可是因為其長期存在於系統之中。使用不當easy出錯.所以普通用戶一般不建議使用。
消息緩沖能夠不再局限於父子進程。而同意隨意進程通過共享消息隊列來實現進程間通信,並由系統調用函數來實現消息發送和接收之間的同步,從而使得用戶在使用消息緩沖進行通信時不再須要考慮同步問題,使用方便。可是信息的復制須要額外消耗CPU的時間,不適宜於信息量大或操作頻繁的場合。
共享內存針對消息緩沖的缺點改而利用內存緩沖區直接交換信息,無須復制。快捷、信息量大是其長處。
可是共享內存的通信方式是通過將共享的內存緩沖區直接附加到進程的虛擬地址空間中來實現的,因此。這些進程之間的讀寫操作的同步問題操作系統無法實現。必須由各進程利用其它同步工具解決。另外,因為內存實體存在於計算機系統中。所以僅僅能由處於同一個計算機系統中的諸進程共享。
不方便網絡通信。
共享內存塊提供了在隨意數量的進程之間進行高效雙向通信的機制。
每一個使用者都能夠讀取寫入數據。可是全部程序之間必須達成並遵守一定的協議,以防止諸如在讀取信息之前覆寫內存空間等競爭狀態的出現。
不幸的是,Linux無法嚴格保證提供對共享內存塊的獨占訪問,甚至是在您通過使用IPC_PRIVATE創建新的共享內存塊的時候也不能保證訪問的獨占性。 同一時候,多個使用共享內存塊的進程之間必須協調使用同一個鍵值。
Linux進程間通信的幾種方式總結--linux內核剖析(七)