1. 程式人生 > >管道,訊息佇列,共享記憶體之間的區別和聯絡

管道,訊息佇列,共享記憶體之間的區別和聯絡

程序間通訊的目的:          

       資料傳輸:一個程序需要將它的資料傳送給另一個程序,傳送的資料量在一個位元組到幾兆位元組之間。
       共享資料:多個程序想要操作共享資料,一個程序對共享資料的修改,別的程序應該立刻看到。
       通知事件:一個程序需要向另一個或一組程序傳送訊息,通知它(它們)發生了某種事件(如程序終止時要通知父程序)。
       資源共享:多個程序之間共享同樣的資源。為了作到這一點,需要核心提供鎖和同步機制。
      程序控制:有些程序希望完全控制另一個程序的執行(如Debug程序),此時控制程序希望能夠攔截另一個程序的所有陷入和異常,並能夠及時知道它的狀態改變。

管道和訊息佇列的區別

管道(PIPE)

       管道通訊方式的中間介質是檔案,通常稱這種檔案為管道檔案。兩個程序利用管道檔案進行通訊時,一個程序為寫程序,另一個程序為讀程序。寫程序通過寫端(傳送端)往管道檔案中寫入資訊;讀程序通過讀端(接收端)從管道檔案中讀取資訊。兩個程序協調不斷地進行寫、讀,便會構成雙方通過管道傳遞資訊的流水線。

管道分為匿名管道和命名管道。

(1)匿名管道:管道是半雙工的,資料只能單向通訊;需要雙方通訊時,需要建立起兩個管道;只能用於父子程序或者兄弟程序之間(具有親緣關係的程序)。

(2)命名管道:可在同一臺計算機的不同程序之間或在跨越一個網路的不同計算機的不同程序之間,支援可靠的、單向或雙向的

資料通訊

       不同於匿名管道之處在於它提供一個路徑名與之關聯,以FIFO的檔案形式存在於檔案系統中。這樣,即使與FIFO的建立程序不存在親緣關係的程序,只要可以訪問該路徑,就能夠彼此通過FIFO相互通訊(能夠訪問該路徑的程序以及FIFO的建立程序之間),因此,通過FIFO不相關的程序也能交換資料。值得注意的是,FIFO嚴格遵循先進先出(first in first out),對管道及FIFO的讀總是從開始處返回資料,對它們的寫則把資料新增到末尾。

       利用系統呼叫pipe()建立一個無名管道檔案,通常稱為無名管道或PIPE;利用系統呼叫mknod()建立一個命名管道檔案,通常稱為有名管道或FIFO。PIPE是一種非永久性的管道通訊機構,當它訪問的程序全部終止時,它也將隨之被撤消;它也不能用於不同族系的程序之間的通訊。而FIFO是一種永久的管道通訊機構,它可以彌補PIPE的不足。管道檔案被建立後,使用open()將檔案進行開啟,然後便可對它進行讀寫操作,通過系統呼叫write()和read()來實現。通訊完畢後,可使用close()將管道檔案關閉。因為匿名管道的檔案是記憶體中的特殊檔案,而且是不可見的,命名管道的檔案是硬碟上的裝置檔案,是可見的。

訊息佇列(message queue)

訊息佇列與命名管道類似,但少了開啟和關閉管道方面的複雜性。使用訊息佇列並未解決我們在使用命名管道時遇到的一些問題,如管道滿時的阻塞問題。訊息佇列提供了一種在兩個不相關程序間傳遞資料的簡單有效的方法。與命名管道相比:訊息佇列的優勢在於,它獨立於傳送和接收程序而存在,這消除了在同步命名管道的開啟和關閉時可能產生的一些困難。訊息佇列提供了一種從一個程序向另一個程序傳送一個數據塊的方法。而且,每個資料塊被認為含有一個型別,接收程序可以獨立地接收含有不同型別值的資料塊。

優點:

      A. 我們可以通過傳送訊息來幾乎完全避免命名管道的同步和阻塞問題。

      B. 我們可以用一些方法來提前檢視緊急訊息。

      C.  訊息佇列可以支援多個程序,多個程序可以讀寫訊息佇列,即訊息佇列可以實現多對多,而管道只能是點對點。

      D.  訊息佇列無需固定的讀寫程序,任何程序都可以讀寫

缺點:

      A. 與管道一樣,每個資料塊有一個最大長度的限制。

      B. 系統中所有佇列所包含的全部資料塊的總長度也有一個上限。

Linux系統中有兩個巨集定義:

     MSGMAX, 以位元組為單位,定義了一條訊息的最大長度。

     MSGMNB, 以位元組為單位,定義了一個佇列的最大長度。

共享記憶體比管道和訊息佇列效率高的原因

       共享記憶體是程序間通訊中最簡單的方式之一。共享記憶體允許兩個或更多程序訪問同一塊記憶體,就如同 malloc() 函式向不同程序返回了指向同一個實體記憶體區域的指標。當一個程序改變了這塊地址中的內容的時候,其它程序都會察覺到這個更改。

       因為所有程序共享同一塊記憶體,共享記憶體在各種程序間通訊方式中具有最高的效率。訪問共享記憶體區域和訪問程序獨有的記憶體區域一樣快,並不需要通過系統呼叫或者其它需要切入核心的過程來完成。同時它也避免了對資料的各種不必要的複製。
       因為系統核心沒有對訪問共享記憶體進行同步,您必須提供自己的同步措施。例如,在資料被寫入之前不允許程序從共享記憶體中讀取資訊、不允許兩個程序同時向同一個共享記憶體地址寫入資料等。解決這些問題的常用方法是通過使用訊號量進行同步。

       共享記憶體塊提供了在任意數量的程序之間進行高效雙向通訊的機制。每個使用者都可以讀取寫入資料,但是所有程式之間必須達成並遵守一定的協議,以防止諸如在讀取資訊之前覆寫記憶體空間等競爭狀態的出現。不幸的是,Linux無法嚴格保證提供對共享記憶體塊的獨佔訪問,甚至是在您通過使用IPC_PRIVATE建立新的共享記憶體塊的時候也不能保證訪問的獨佔性。 同時,多個使用共享記憶體塊的程序之間必須協調使用同一個鍵值。     

       共享記憶體區是最快的可用IPC形式,一旦這樣的記憶體區對映到共享它的程序的地址空間,這些程序間資料的傳遞就不再通過執行任何進入核心的系統呼叫來傳遞彼此的資料,節省了時間。

共享記憶體和訊息佇列,FIFO,管道傳遞訊息的區別:

   ——訊息佇列,FIFO,管道的訊息傳遞方式一般為
          1:伺服器得到輸入
          2:通過管道,訊息佇列寫入資料,通常需要從程序拷貝到核心。
          3:客戶從核心拷貝到程序
          4:然後再從程序中拷貝到輸出檔案
      上述過程通常要經過4次拷貝,才能完成檔案的傳遞。
       ——共享記憶體只需要
           1:從輸入檔案到共享記憶體區
           2:從共享記憶體區輸出到檔案

 上述過程不涉及到核心的拷貝,所以花的時間較少。