這部分參考文獻2:詳細內容打開鏈接看
程序員必須讓擁有依賴關系的進程集協調,這樣才能達到進程的共同目標。可以使用兩種技術來達到協調。第一種技術在具有通信依賴關系的兩個進程間傳遞信息。這種技術稱做進程間通信(interprocess communication)。第二種技術是同步,當進程間相互具有合作依賴時使用。這兩種類型的依賴關系可以同時存在。
一般而言,進程有單獨的地址空間。我們可以了解下可執行程序被裝載到內存后建立的一系列映射等理解這一點。如此以來意味着如果我們有兩個進程(進程A和進程B),那么,在進程A中聲明的數據對於進程B是不可用的。而且,進程B看不到進程A中發生的事件,反之亦然。如果進程A和B一起工作來完成某個任務,必須有一個在兩個進程間通信信息和時間的方法。我們這里可以去看看基本的進程組件。注意進程有一個文本、數據以及堆棧片斷。進程可能也有從自由存儲空間中分配的其它內存。進程所占有的數據一般位於數據片斷、堆棧片斷或進程的動態分配內存中。數據對於其它進程來說是受保護的。為了讓一個進程訪問另外一個進程的數據,必須最終使用操作系統調用。與之類似,為了讓一個進程知道另一個進程中文本片斷中發生的事件,必須在進程間建立一種通信方式。這也需要來自操作系統API的幫助。當進程將數據發送到另一進程時,稱做IPC(interprocess communication,進程間通信)。
下面先列舉幾種不同類型的進程間通信方式:
進程間通信 | 描述 |
環境變量/文件描述符 | 子進程接受父進程環境數據的拷貝以及所有文件描述符。父進程可以在它的數據片斷或環境中設置一定的變量,同時子進程接收這些值。父進程可以打開文件,同時推進讀/寫指針的位置,而且子進程使用相同的偏移訪問該文件。 |
命令行參數 | 在調用exec或派生函數期間,命令行參數可以傳遞給子進程。 |
管道 | 用於相關和無關進程間的通信,而且形成兩個進程間的一個通信通道,通常使用文件讀寫程序訪問。 |
共享內存(動態數據交換,Dynamic data exchange) |
使用客戶機/服務器模型(C/S),服務器對客戶的數據 或動作請求作出反應。 |
DDE | 兩個進程之外的內存塊,兩個進程均可以訪問它。 |
一、環境變量、文件描述符:
當創建一個子進程時,它接受了父進程許多資源的拷貝。子進程接受了父進程的文本、堆棧
以及數據片斷的拷貝。子進程也接受了父進程的環境數據以及所有文件描述符的拷貝。子進
程從父進程繼承資源的過程創造了進程間通信的一個機會。父進程可以在它的數據片斷或環
境中設置一定的變量,子進程於是接受這些值。同樣,父進程也可以打開一個文件,推進到
文件內的期望位置,子進程接着就可以在父進程離開讀/寫指針的准確位置訪問該文件。
這類通信的缺陷在於它是單向的、一次性的通信。也就是說,除了文件描述外,如果子進程
繼承了任何其它數據,也僅僅是父進程拷貝的所有數據。 一旦創建了子進程,由子進程對
這些變量的任何改變都不會反映到父進程的數據中。同樣,創建子進程后,對父進程數據的
任何改變也不會反映到子進程中。所以,這種類型的進程間通信更像指揮棒傳遞。一旦父進
程傳遞了某些資源的拷貝,子進程對它的使用就是獨立的,必須使用原始傳遞資源。
二、命令行參數:
通過命令行參數(command-line argument)可以完成另一種單向、一次性的進程間通信
我前面的文章已經提到過使用命令行參數。命令行參數在調用一個exec或派生調用操作系
統時傳遞給子進程。命令行參數通常在其中一個參數中作為NULL終止字符串傳遞給exec
或派生函數調用。這些函數可以按單向、一次性方式給子進程傳遞值。WINDOWS有調用執行
exe程序的API。大家可以去參考一下ShellExecuteA函數相關。
三、管道通信:
繼承資源以及命令行參數是最簡單形式的進程間通信。它們同時有兩個主要限制。除了文件
描述符外,繼承資源是IPC的單向、一次性形式。傳遞命令參數也是單向、一次性的IPC
方法。這些方法也只有限制於關聯進程,如果不關聯,命令行參數和繼承資源不能使用。還
有另一種結構,稱做管道(Pipe),它可以用於在關聯進程間以及無關聯進程間進行通信。
管道是一種數據結構,像一個序列化文件一樣訪問。它形成了兩個進程間的一種通信渠道。
管道結構通過使用文本和寫方式來訪問。如果進程A希望通過管道發送數據給進程B,那么
進程A向管道寫入數據。為了讓進程B接收此數據,進程B必須讀取管道,與命令行參數的
IPC形式不一樣。管道可以雙向通信。兩進程間的數據流是雙向通信的。管道可以在程序的
整個執行期間使用,在進程間發送和接收數據。所以,管道充當可訪問管道的進程間的一種
可活鏈接,有兩種基本管道類型:
1. 匿名管道
2. 命名管道
上面的圖可以看出在沒有管道時,兩進程是不能互寫的。
建立管道后就可以相互通信了。
四、 共享內存
共享內存也可以實現進程間的通信。進程需要可以被其他進程瀏覽的內存塊。希望訪問這個內存塊的其他進程請求對它的訪問,或由創建它的進程授予訪問內存塊的權限。可以訪問特定內存塊的所有進程對它具有即時可見性。共享內存被映射到使用它的每個進程的地址空間。所以,它看起來像是另一個在進程內聲明的變量。當一個進程寫共享內存,所有的進程都立即知道寫入的內容,而且可以訪問。
進程間共享內存的關系與函數間全局變量的關系相似。程序中的所有函數都可以使用全局變量的值。同樣,共享內存塊可以被正在執行的所有進程訪問。內存塊可能共享一個邏輯地址,進程也可以共享某些物理地址。
共享內存塊的創建必須由一個系統API調用來完成。在WIN32環境中,使用CreateFileMapping()、MapViewOfFile()以及MapViewOfFileEx() API能很好地完成。
共享內存分配位於WIN32系統中2~3GB地址范圍內。一旦調用MapViewOfFile()和MapViewOfFileEx(),共享文件映射對象的所有進程都可以立即訪問此內存塊,而且在需要時,可以讀寫此內存塊。
五、動態數據交換
動態數據交換( dynamic data exchange ) 是當今可用的進程間通信最強大和完善的形式之一。動態數據交換使用消息傳遞、共享內存、事務協議、客戶/服務器范疇、同步規則以及會話協議來讓數據和控制信息在進程間流動。動態數據交換對話( dynamic data exchange session, DDE )的基本模型是客戶、服務器。服務器對來自客戶的數據或動作作出反應。客戶和服務器可以以多種關系來通信。
一個服務器可以與任意數量的客戶通信。一個客戶也可以與任意數量的服務器通信。單個DDE代理既可以是客戶,也可以是服務器。也就是說,進程可以從一個正為另一個進程執行服務的DDE代理請求服務。
下部分參考文獻1:
進程間通信主要包括管道, 系統IPC(包括消息隊列,信號量,共享存儲), SOCKET.
Windows系統進程間通信
Windows提供了多種機制,使得應用程序之間能夠快速、方便地共享數據和信息。這些機制包括RPC、COM、OLE、DDE、消息、剪切板、郵件槽、管道、套接字等。但是,如果在同一台機器上的多個進程間進行通信的話,那么上面的機制都與共享內存有關。這在Windows上稱作內存映射文件。
這種數據共享機制是通過讓兩個或多個進程映射同一文件映射對象的視圖來實現,這意味着進程間共享相同的物理存儲頁面。因此,當一個進程在文件映射對象的視圖中寫入數據時,其他的進程會在它們的視圖中立刻看到變化。但是,對多個進程共享同一個文件映射對象來說,所有進程使用的文件映射對象的名稱必須完全相同[1]。
Linux系統進程間通信
linux下的進程通信手段基本上是從Unix平台上的進程通信手段繼承而來的。而對Unix發展做出重大貢獻的兩大主力AT&T的貝爾實驗室及BSD(加州大學伯克利分校的伯克利軟件發布中心)在進程間通信方面的側重點有所不同。前者對Unix早期的進程間通信手段進行了系統的改進和擴充,形成了“system V IPC”,通信進程局限在單個計算機內;后者則跳過了該限制,形成了基於套接口(socket)的進程間通信機制。Linux則把兩者繼承了下來。
Linux下的進程間通信機制大致包括:管道、信號(在Windows上成為消息)、信號隊列(實際是消息鏈表)、共享內存、信號量、套接字。
共同點
由上面的分析可以看出兩個操作系統共有的且用的較多的進程間通信機制有:管道、消息、共享內存和套接字。簡介如下:
管道(Pipe)及有名管道(named pipe):管道可用於具有親緣關系進程間的通信,有名管道克服了管道沒有名字的限制,因此,除具有管道所具有的功能外,它還允許無親緣關系進程間的通信。
信號或者消息(Signal):信號是比較復雜的通信方式,用於通知接受進程有某種事件發生,除了用於進程間通信外,進程還可以發送信號給進程本身。
共享內存:使得多個進程可以訪問同一塊內存空間,是最快的可用IPC形式。是針對其他通信機制運行效率較低而設計的。往往與其它通信機制,如信號量結合使用,來達到進程間的同步及互斥。
套接口(Socket):更為一般的進程間通信機制,可用於不同機器之間的進程間通信。
總結
消息隊列是消息的鏈接表,消息隊列克服了信號承載信息量少,管道只能承載無格式字節流以及緩沖區大小受限等缺點;而信號量主要作為進程間以及同一進程不同線程之間的同步手段。
個人認為:管道、剪貼板、共享內存都是基於共享內存的方式。而消息、消息隊列和套接字的都是基於發消息的機制,只是看是在同一個機器上發還是在網絡中發消息而已(套接字可以看做在網絡中發送消息)。至於RPC、COM、OLE、DDE主要是在客戶端和服務器端生成一個統一的接口。也就是說這幾個通信手段其實就相當於網絡上的協議。在同一層通信的協議不管下一層,好像這兩層直接建立了聯系。這個基本的思想是在本地建立類似存根代碼的代碼,而在遠程建立類似樁代碼的代碼來進行連接。
這上面的通信方式中,剪切板和匿名管道只能實現同一機器上兩個進程間的通信,而信號量、消息、消息隊列和共享內存也只能在同一台機器上的多個進程間通信;但是命名管道、郵件槽和套接字不僅可以實現同一機器上的兩個進程的通信,還可以實現跨網絡的進程間通信;另外,油槽和套接字可以實現一對多的通信,而命名管道只能是點對點的單一通信,但油槽的缺點是數據量較小,通常都是在424字節以下,如果數據量較大,則可以采用命名管道和套接字的方式來完成。綜上:在跨網絡通信中套接字無疑是最優秀的通信方式,這或許是伯克利開發套接字來進行網絡通信的初衷吧(傳統通信方式不好用)。
參考:
1:http://blog.sina.com.cn/s/blog_6002b97001013wec.html
2:http://blog.csdn.net/liuzhanchen1987/article/details/7452910