Linux/Unix 進程間通信IPC

1 IPC 工具分類

圖43-1總結了UNIX系統上各種通信和同步工具,並根據功能將它們分成了三類。

  • 通信:這些工具關注進程之間的數據交換。
  • 同步:這些進程關注進程和線程操作之間的同步。
  • 信號:儘管信號的主要作用並不在此,但在特定場景下仍然可以將它作爲一種同步技術。更罕見的是信號還可以作爲一種通信技術:信號編號本身是一種形式的信息, 並且可以在實時信號上綁定數據(一個整數或指針)

儘管其中一些工具關注的是同步,但通用術語進程間通信(IPC) 通常指代所有這些工具。

 

2 通信工具

圖43-1中列出的各種通信工具允許進程間相互交換數據。(這些工具還可以用來在同一個進程中不同線程之間交換數據,但很少需要這樣做,因爲線程之間可以通過共享全局變量來交互。

通信工具分爲兩類:

  • 數據傳輸工具:區分這些工具的關鍵因素是寫入和讀取的概念。爲了進行通信,個進程將數據寫入到IPC工具中,另一進程從中讀取數據。這些工具要求在用戶內存和內核內存之間進行兩次數據傳輸:一次傳輸是在寫入的時候從用戶內存到內核內存,另一次傳輸是在讀取的時候從內核內存到用戶內存。
  • 共享內存:共享內存允許進程通過將數據放到由進程間共享的一塊內存中以完成信息的交換。(內核通過將每個進程中的頁表條目指向同一個RAM分頁來實現這一功能)一個進程可以通過將數據放到共享內存塊中使得其他進程讀取這些數據。由於通信無需系統調用以及用戶內存和內核內存之間的數據傳輸,因此共享內存的速度非常快。

可以進一步將數據傳輸工具分成下列類別:

  • 字節流:通過管道、FIFO以及數據報socket交換的數據是一個無分隔符的字節流。每個讀取操作可能會從IPC工具中讀取任意數量的字節,不管寫者寫入的塊的大小是什麼。
  • 消息:通過SystemV消息隊列、POSIX消息隊列以及數據報socket交換的數據是以分隔符分隔的消息。每個讀取操作讀取由寫者寫入的一整條消息,無法只讀取部分消息,而把剩餘部分留在IPC工具中,也無法在一個讀取操作中讀取多條消息。
  • 僞終端:僞終端是一種在特殊情況下使用的通信工具,在64章將會介紹有關僞終端的詳細信息。

數據傳輸工具和共享內存之間的差別包括以下幾個方面。

  • 儘管一個數據傳輸工具可能會有多個讀取者,但讀取操作是具有破壞性的。讀取操作會消耗數據,其他進程將無法獲取所消耗的數據。在socket中可以使用MSG_PEEK標記來執行非破壞性讀取(參見61.3節)。UDP socket 允許將一條消息廣播或組播到多個接收者處(參見61.12節)。
  • 讀取者和寫者進程之間的同步是原子的。如果一個讀取者試圖從一個當前不包含數據的數據傳輸工具中讀取數據,那麼在默認情況下讀取操作會被阻塞直至一些進程向該工具寫入了數據。

3 同步工具

通過同步可以防止進程執行諸如同時更新一塊共享內存或同時更新文件的同一個數據塊之類的操作。

UNIX系統提供了下列同步工具。

  • 信號量: 一個信號量是一個由內核維護的整數,其值永遠不會小於0。一個進程可以增加或減小一個信號量的值。如果一個進程試圖將信號量的值減小到小於0,那麼內核會阻塞該操作直至信號量的值增長到允許執行該操作的程度。(或者進程可以要求執行一個非阻塞操作,那麼就不會發生阻塞,內核會讓該操作立即返回並返回一個標示無法立即執行該操作的錯誤。)最常用的信號量是二元信號量:一個值只能是0或1的信號量,但處理一類共享資源擁有多個實例的應用程序需要使用最大值等於共享資源數量的信號量。
  • 文件鎖: 文件鎖是設計用來協調操作同一件的多個進程的動作的一種同步方法。文件鎖分爲兩類:讀(共享)鎖和寫(互斥)鎖。Linux通過flock()和fcntl()系統調用來提供文件加鎖工具。flock()系統調用提供了一種簡單的加鎖機制,允許進程將一個共享或互斥鎖加到整個文件上。由於功能有限,現在已經很少使用flock()這個加鎖工具了。fcntl()系統調用提供了記錄加鎖,允許進程在同一文件的不同區域上加上多個讀鎖和寫鎖。
  • 互斥體和條件變量:這些同步工具通常用於POSIX線程,第30章對此進行了介紹。

在執行進程間同步時通常需要根據功能需求來選擇工具。當協調對文件的訪問時文件記錄加鎖通常是最佳的選擇,而對於協調對其他共享資源的訪問來講,信號量通常是更佳的選擇。

4 IPC工具比較

下面介紹在確定選擇何種IPC工具時通常需要考慮的事項。

1. IPC對象標識和打開對象的句柄

要訪問一個IPC對象,進程必須要通過某種方式來標識出該對象,一旦將對象“打開”之後,進程必須要使用某種句柄來引用該打開着的對象。表43-1對各種類型的IPC工具的屬性進行了總結。

功能

各種IPC工具在功能上是存在差異的,因此在確定使用何種工具時需要考慮這些差異。

  • 數據傳輸工具提供了讀取和寫入操作,傳輸的數據只供一個讀者進程消耗。內核會自動處理讀者和寫者之間的流控以及同步(這樣當讀者試圖從當前爲空的工具中讀取數據時將會阻塞)。在很多應用程序設計中,這個模型都表現得很好。
  • 其他應用程序設計則更適合採用共享內存的方式。共享內存需要的同步處理(可能還會有流控)會增加共享內存設計的複雜性。在需要維護共享狀態(如共享數據結構)的應用程序中,這個模型表現得很好。

關於各種數據傳輸工具,下 面幾點是值得注意的。

  • 一些數據傳輸工具以字節流的形式傳輸數據(管道、FIFO 以及流socket),另一些則是面向消息的(消息隊列和數據報socket)。到底選擇何種方法則需要依賴於應用程序。(應用程序也可以在一個字節流工具上應用面向消息的模型,這可以通過使用分隔字符、固定長度的消息,或對整條消息長度進行編碼的消息頭來實現,具體可參考44.8節)。
  • 與其他數據傳輸工具相比,SystemV和POSIX消息隊列特有的一個特性是它們能夠給消息賦一個數值類型或優先級,這樣遞送消息的順序就可以與發送消息的順序不同了。
  • 管道、FIFO 以及socket是使用文件描述符來實現的。這些IPC工具都支持 I/O 多路複用( select()和poll()系統調用)、信號驅動的I/O、以及Linux特有的epoll API。這些技術的主要優勢在於它們允許應用程序同時監控多個文件描述符以判斷是否可以在某些文件描述符上執行I/O操作。與之相比,System V消息隊列沒有使用文件描述符,因此並不支持這些技術。
  • POSIX消息隊列提供了一個通知工具,當一條消息進入了一個之前爲空的隊列中時可以使用它來向進程發送信號或實例化一個新線程。
  • UNIX domain socket提供了一個特性:允許在進程間傳遞文件描述符。這樣一個進程就能夠打開一個文件並使之對另一個本來無法訪問該文件的進程可用。
  • UDP (Internet domain datagram) socket 允許一個發送者向多個接收者廣播或組播一條消息

關於進程同步工具,下面幾點是值得注意的。

  • 使用fcnt()加上的記錄鎖由加鎖的進程擁有。內核使用這種所有權屬性來檢測死鎖。如果發生了死鎖,那麼內核會拒絕其中一個進程的加鎖請求,因此會在fcntl()調用中返回一個錯誤標示出死鎖的發生。SystemV和POSIX信號量並沒有所有權屬性,因此內核不會爲信號量進行死鎖檢測。
  • 當使用fcnt()獲得記錄鎖的進程終止之後會自動釋放該記錄鎖。SystemV信號量提供了一個類似的特性,即“撤銷”特性,但這個特性僅在部分場景中可靠(參見47.8節)。POSIX信號量並沒有提供類似的特性。

網絡通信

在圖43-1中給出所有IPC方法中,只有socket允許進程通過網絡來通信。socket一般用於兩個域中:一個是UNIX domain,它允許位於同一系統上的進程進行通信;另一個是Internetdomain,它允許位於通過TCP/IP網絡進行連接的不同主機上的進程進行通信。

可移植性

從可移植性的角度來看,System V IPC要優於POSIX IPC。

但是System V IPC是複雜的,例如:

    • System V IPC工具是無連接的,它們沒有提供引用一個打開的IPC對象的句柄(類似於文件描述符)的概念。這意味着內核無法維護當前使用該對象的進程的引用計數,其結果是應用程序需要使用額外的代碼來知道何時可以安全地刪除一個對象。
    • System V IPC 工具的編程接口 與傳統的UNIX I/O模型是不一致的(它們使用整數鍵值和IPC標識符,而不是路徑名和文件描述符),並且這個編程接口也過於複雜了。

相反,內核會爲POSIX IPC對象記錄打開的引用數,這樣就簡化了何時刪除對象的決策。此外,POSIX IPC提供的接口更加簡單並且與傳統的UNIX模型也更加一致。

可訪問性和持久性

可訪問性:權限模型控制着哪些進程能夠訪問對象。一些IPC工具(管道、匿名內存映射)被標記成只允許相關進程訪問。這裏“相關”指通過fork()關聯的。

術語持久性是指一個IPC工具的生命週期。持久性有三種。

  • 進程持久性:只要存在一個進程持有進程持久的IPC對象,那麼該對象的生命週期就不會終止。如果所有進程都關閉了對象,那麼與該對象的所有內核資源都會被釋放,所有未讀取的數據會被銷燬。管道、FIFO 以及socket是進程持久的IPC工具。
  • 內核持久性:只有當顯式地刪除內核持久的IPC對象或系統關閉時,該對象纔會銷燬。這意味着一個進程可以創建一個對象,向其中寫入數據,然後關閉該對象(或終止)。在後面某個時刻,另一個進程可以打開該對象,然後從中讀取數據。
  • 文件系統持久性:具備文件系統持久性的IPC對象會在系統重啓的時候保持其中的信息,這種對象一直存在直至被顯式地刪除。唯一種具備文件系統持久性的IPC對象是基於內存映射文件的共享內存。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章