Linux環境進程間通信的方式

Linux環境下,進程間的通信的方式有:管道、有名管道,信號,消息隊列,信號燈,共享內存等。

管道(Anonymous Pipes)與有名管道(Named Pipes) 1

Linux 進程間通信的幾種主要手段之中,管道和有名管道是最早的進程間通信機制之一,管道可用於具有親緣關係進程間的通信,有名管道克服了管道沒有名字的限制,因此,除具有管道所具有的功能外,它還允許無親緣關係進程間的通信。

管道是Linux支持的最初Unix IPC形式之一,具有以下特點:

  • 管道是半雙工的,數據只能向一個方向流動;需要雙方通信時,需要建立起兩個管道;

  • 只能用於父子進程或者兄弟進程之間(具有親緣關係的進程,這裏的親緣關係指的是具有共同的祖先);

  • 單獨構成一種獨立的文件系統:管道對於管道兩端的進程而言,就是一個文件,但它不是普通的文件,它不屬於某種文件系統,而是自立門戶,單獨構成一種文件系統,並且只存在與內存中。

  • 數據的讀出和寫入:一個進程向管道中寫的內容被管道另一端的進程讀出。寫入的內容每次都添加在管道緩衝區的末尾,並且每次都是從緩衝區的頭部讀出數據。

管道的主要侷限性正體現在它的特點上:

  • 只支持單向數據流;

  • 只能用於具有親緣關係的進程之間;

  • 沒有名字;

  • 管道的緩衝區是有限的(管道只存在於內存中,在管道創建時,爲緩衝區分配一個頁面大小);

  • 管道所傳送的是無格式字節流,這就要求管道的讀出方和寫入方必須事先約定好數據的格式,比如多少字節算作一個消息(或命令、或記錄)等等;

管道應用的一個重大限制是它沒有名字,因此,只能用於具有親緣關係的進程間通信,在有名管道(named pipe或FIFO)提出後,該限制得到了克服。FIFO不同於管道之處在於它提供一個路徑名與之關聯,以FIFO的文件形式存在於文件系統中。這樣,即使與FIFO的創建進程不存在親緣關係的進程,只要可以訪問該路徑,就能夠彼此通過FIFO相互通信(能夠訪問該路徑的進程以及FIFO的創建進程之間),因此,通過FIFO不相關的進程也能交換數據。值得注意的是,FIFO嚴格遵循先進先出(first in first out),對管道及FIFO的讀總是從開始處返回數據,對它們的寫則把數據添加到末尾。它們不支持諸如lseek()等文件定位操作。

小結:

管道常用於兩個方面:(1)在shell中時常會用到管道(作爲輸入輸出的重定向),在這種應用方式下,管道的創建對於用戶來說是透明的;(2)用於具有親緣關係的進程間通信,用戶自己創建管道,並完成讀寫操作。

FIFO可以說是管道的推廣,克服了管道無名字的限制,使得無親緣關係的進程同樣可以採用先進先出的通信機制進行通信。

管道和FIFO的數據是字節流,應用程序之間必須事先確定特定的傳輸”協議”,採用傳播具有特定意義的消息。

要靈活應用管道及FIFO,理解它們的讀寫規則是關鍵。

信號(Signals) 2

信號本質

信號是在軟件層次上對中斷機制的一種模擬,在原理上,一個進程收到一個信號與處理器收到一箇中斷請求可以說是一樣的。信號是異步的,一個進程不必通過任何操作來等待信號的到達,事實上,進程也不知道信號到底什麼時候到達。

信號是進程間通信機制中唯一的異步通信機制,可以看作是異步通知,通知接收信號的進程有哪些事情發生了。信號機制經過POSIX實時擴展後,功能更加強大,除了基本通知功能外,還可以傳遞附加信息。

信號來源

信號事件的發生有兩個來源:硬件來源(比如我們按下了鍵盤或者其它硬件故障);軟件來源,最常用發送信號的系統函數是kill, raise, alarm和setitimer以及sigqueue函數,軟件來源還包括一些非法運算等操作。

消息隊列(Message Queues) 3

消息隊列(也叫做報文隊列)能夠克服早期unix通信機制的一些缺點。作爲早期unix通信機制之一的信號能夠傳送的信息量有限,後來雖然POSIX 1003.1b在信號的實時性方面作了拓廣,使得信號在傳遞信息量方面有了相當程度的改進,但是信號這種通信方式更像”即時”的通信方式,它要求接受信號的進程在某個時間範圍內對信號做出反應,因此該信號最多在接受信號進程的生命週期內纔有意義,信號所傳遞的信息是接近於隨進程持續的概念(process-persistent),見 附錄;管道及有名管道及有名管道則是典型的隨進程持續IPC,並且,只能傳送無格式的字節流無疑會給應用程序開發帶來不便,另外,它的緩衝區大小也受到限制。

消息隊列就是一個消息的鏈表。可以把消息看作一個記錄,具有特定的格式以及特定的優先級。對消息隊列有寫權限的進程可以向中按照一定的規則添加新消息;對消息隊列有讀權限的進程則可以從消息隊列中讀走消息。消息隊列是隨內核持續的(參見 附錄)。

目前主要有兩種類型的消息隊列:POSIX消息隊列以及系統V消息隊列,系統V消息隊列目前被大量使用。考慮到程序的可移植性,新開發的應用程序應儘量使用POSIX消息隊列。

信號燈(信號量,Semaphores) 4

信號燈與其他進程間通信方式不大相同,它主要提供對進程間共享資源訪問控制機制。相當於內存中的標誌,進程可以根據它判定是否能夠訪問某些共享資源,同時,進程也可以修改該標誌。除了用於訪問控制外,還可用於進程同步。信號燈有以下兩種類型:

  • 二值信號燈:最簡單的信號燈形式,信號燈的值只能取0或1,類似於互斥鎖。

    注:二值信號燈能夠實現互斥鎖的功能,但兩者的關注內容不同。信號燈強調共享資源,只要共享資源可用,其他進程同樣可以修改信號燈的值;互斥鎖更強調進程,佔用資源的進程使用完資源後,必須由進程本身來解鎖。

  • 計算信號燈:信號燈的值可以取任意非負值(當然受內核本身的約束)。

總結:

信號燈與其它進程間通信方式有所不同,它主要用於進程間同步。通常所說的系統V信號燈實際上是一個信號燈的集合,可用於多種共享資源的進程間同步。每個信號燈都有一個值,可以用來表示當前該信號燈代表的共享資源可用(available)數量,如果一個進程要申請共享資源,那麼就從信號燈值中減去要申請的數目,如果當前沒有足夠的可用資源,進程可以睡眠等待,也可以立即返回。當進程要申請多種共享資源時,linux可以保證操作的原子性,即要麼申請到所有的共享資源,要麼放棄所有資源,這樣能夠保證多個進程不會造成互鎖。

共享內存(Shared memory) 5

共享內存可以說是最有用的進程間通信方式,也是最快的IPC形式。兩個不同進程A、B共享內存的意思是,同一塊物理內存被映射到進程A、B各自的進程地址空間。進程A可以即時看到進程B對共享內存中數據的更新,反之亦然。由於多個進程共享同一塊內存區域,必然需要某種同步機制,互斥鎖和信號量都可以。

採用共享內存通信的一個顯而易見的好處是效率高,因爲進程可以直接讀寫內存,而不需要任何數據的拷貝。對於像管道和消息隊列等通信方式,則需要在內核和用戶空間進行四次的數據拷貝,而共享內存則只拷貝兩次數據:一次從輸入文件到共享內存區,另一次從共享內存區到輸出文件。實際上,進程之間在共享內存時,並不總是讀寫少量數據後就解除映射,有新的通信時,再重新建立共享內存區域。而是保持共享區域,直到通信完畢爲止,這樣,數據內容一直保存在共享內存中,並沒有寫回文件。共享內存中的內容往往是在解除映射時才寫回文件的。因此,採用共享內存的通信方式效率是非常高的。

套接字(Socket) 6

套接字(Socket)是由Berkeley在BSD系統中引入的一種基於連接的IPC,是對網絡接口(硬件)和網絡協議(軟件)的抽象。它既解決了無名管道只能在相關進程間單向通信的問題,又解決了網絡上不同主機之間無法通信的問題。

套接字有三個屬性:域(domain)、類型(type)和協議(protocol),對應於不同的域,套接字還有一個地址(address)來作爲它的名字。

域(domain)指定了套接字通信所用到的協議族,最常用的域是AF_INET,代表網絡套接字,底層協議是IP協議。對於網絡套接字,由於服務器端有可能會提供多種服務,客戶端需要使用IP端口號來指定特定的服務。AF_UNIX代表本地套接字,使用Unix/Linux文件系統實現。

IP協議提供了兩種通信手段:流(streams)和數據報(datagrams),對應的套接字類型(type)分別爲流式套接字和數據報套接字。流式套接字(SOCK_STREAM)用於提供面向連接、可靠的數據傳輸服務。該服務保證數據能夠實現無差錯、無重複發送,並按順序接收。流式套接字使用TCP協議。數據報套接字(SOCK_DGRAM)提供了一種無連接的服務。該服務並不能保證數據傳輸的可靠性,數據有可能在傳輸過程中丟失或出現數據重複,且無法保證順序地接收到數據。數據報套接字使用UDP協議。

一種類型的套接字可能可以使用多於一種的協議來實現,套接字的協議(protocol)屬性用於指定一種特定的協議。

附錄:

進程間通信(IPC,inter-process communication)隨進程持續、隨內核持續以及隨文件系統持續的定義:

  1. 隨進程持續:IPC一直存在到打開IPC對象的最後一個進程關閉該對象爲止。如管道和有名管道;
  2. 隨內核持續:IPC一直持續到內核重新自舉或者顯示刪除該對象爲止。如消息隊列、信號燈以及共享內存等;
  3. 隨文件系統持續:IPC一直持續到顯示刪除該對象爲止。

  1. http://www.ibm.com/developerworks/cn/linux/l-ipc/part1/index.html#authorN10019 “Linux環境進程間通信(一):管道及有名管道”
  2. http://www.ibm.com/developerworks/cn/linux/l-ipc/part2/index1.html “Linux環境進程間通信(二): 信號(上)”
  3. http://www.ibm.com/developerworks/cn/linux/l-ipc/part3/index.html “Linux環境進程間通信(三):消息隊列 ”
  4. http://www.ibm.com/developerworks/cn/linux/l-ipc/part4/index.html “Linux環境進程間通信(四):信號燈”
  5. http://www.ibm.com/developerworks/cn/linux/l-ipc/part5/index1.html “Linux環境進程間通信(五): 共享內存(上)”
  6. http://www.cnblogs.com/wangkangluo1/archive/2012/05/14/2498786.html “Linux IPC總結(全)”
發佈了91 篇原創文章 · 獲贊 58 · 訪問量 54萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章