共享記憶體和訊息佇列原理概述 分布式系統的通訊

2022-03-14 09:45:38 字數 4791 閱讀 4724

作業系統內的併發執行程序可以是獨立的也可以是協作的:

提供環境允許程序協作,具有許多理由:

協作程序需要有一種程序間通訊機制(簡稱 ipc),以允許程序相互交換資料與資訊。程序間通訊有兩種基本模型:共享記憶體和訊息傳遞(訊息佇列):

圖 1 給出了這兩種模型的對比。

圖 1 通訊模型

上述兩種模型在作業系統中都常見,而且許多系統也實現了這兩種模型。訊息傳遞對於交換較少數量的資料很有用,因為無需避免衝突。對於分布式系統,訊息傳遞也比共享記憶體更易實現。共享記憶體可以快於訊息傳遞,這是因為訊息傳遞的實現經常採用系統呼叫,因此需要消耗更多時間以便核心介入。與此相反,共享記憶體系統僅在建立共享記憶體區域時需要系統呼叫;一旦建立共享記憶體,所有訪問都可作為常規記憶體訪問,無需借助核心。對具有多個處理核系統的最新研究表明,在這類系統上,訊息傳遞的效能要優於共享記憶體。共享記憶體會有快取記憶體一致性問題,這是由共享資料在多個快取記憶體之間遷移而引起的。隨著系統的處理核的數量的日益增加,可能導致訊息傳遞作為 ipc 的首選機制。

採用共享記憶體的程序間通訊,需要通訊程序建立共享記憶體區域。通常,共享記憶體區域駐留在建立共享記憶體段的程序位址空間內。其他希望使用這個共享記憶體段進行通訊的程序應將其附加到自己的位址空間。回憶一下,通常作業系統試圖阻止乙個程序訪問另一程序的記憶體。共享記憶體需要兩個或更多的程序同意取消這一限制,這樣它們通過在共享區域內讀出或寫入來交換資訊。資料的型別或位置取決於這些程序,而不是受控於作業系統。另外,程序負責確保它們不向同一位置同時寫入資料。為了說明協作程序的概念,我們來看一看生產者-消費者問題,這是協作程序的通用範例。生產者程序生成資訊,以供消費者程序消費。例如,編譯器生成的彙編**可供匯程式設計序使用,而且匯程式設計序又可生成目標模組以供引導程式使用。生產者-消費者問題同時還為客戶機-伺服器範例提供了有用的比喻。通常,將伺服器當作生產者,而將客戶機當作消費者。例如,乙個 web 伺服器生成(提供)html 檔案和影象,以供請求資源的 web 客戶瀏覽器使用(讀取)。解決生產者-消費者問題的方法之一是採用共享記憶體。為了允許生產者程序和消費者程序併發執行,應有乙個可用的緩衝區,以被生產者填充和被消費者清空。這個緩衝區駐留在生產者程序和消費者程序的共享記憶體區域內。當消費者使用一項時,生產者可產生另一項。生產者和消費者必須同步,這樣消費者不會試圖消費乙個尚未生產出來的項。緩衝區型別可分兩種:

下面深入分析,有界緩衝區如何用於通過共享記憶體的程序間通訊。以下變數駐留在由生產者和消費者共享的記憶體區域中:12

3456

7#define buffer_size 10

typedefstructitem;

item buffer [buffer_size];

intin = 0;

intout = 0;

共享 buffer 的實現採用乙個迴圈陣列和兩個邏輯指標:in 和 out。變數 in 指向緩衝區的下乙個空位;變數 out 指向緩衝區的第乙個滿位。當in == out時,緩衝區為空;當(in + 1)%buffer size == out時,緩衝區為滿。生產者程序和消費者程序的**為:12

3456

78910

1112

1314

1516

17//生產者程序

while(true)

//消費者程序

item next_consumed;

while(true)

生產者程序有乙個區域性變數 next_produced,以便儲存生成的新項;消費者程序有乙個區域性變數 next_consumed,以便儲存所要使用的新項。

前面講解了協作程序如何可以通過共享記憶體進行通訊。此方案要求這些程序共享乙個記憶體區域,並且應用程式開發人員需要明確編寫**,以訪問和操作共享記憶體。達到同樣效果的另一種方式是,作業系統提供機制,以便協作程序通過訊息傳遞功能進行通訊。訊息傳遞提供一種機制,以便允許程序不必通過共享位址空間來實現通訊和同步。對分布式環境(通訊程序可能位於通過網路連線的不同計算機),這特別有用。例如,可以設計乙個網際網路的聊天程式以便聊天參與者通過交換訊息相互通訊。訊息傳遞工具提供至少兩種操作:send(message) 和 receive(message)。程序傳送的訊息可以是定長的或變長的。如果只能傳送定長訊息,那麼系統級實現就簡單。不過,這一限制使得程式設計任務更加困難。相反,變長訊息要求更複雜的系統級實現,但是程式設計任務變得更為簡單。在整個作業系統設計中,這種折中很常見。如果程序 p 和 q 需要通訊,那麼它們必須互相傳送訊息和接收訊息:它們之間要有通訊鏈路。該鏈路的實現有多種方法。這裡不關心鏈路的物理實現(如共享記憶體、硬體匯流排或網路等),而只關心鏈路的邏輯實現。這裡有幾個方法,用於邏輯實現鏈路和操作 send()/receive():

下面研究這些特徵的相關問題。

命名需要通訊的程序應有乙個方法,以便互相引用。它們可以使用直接或間接的通訊。對於直接通訊,需要通訊的每個程序必須明確指定通訊的接收者或傳送者。採用這種方案,原語 send() 和 receive() 定義如下:

這種方案的通訊鏈路具有以下屬性:

這種方案展示了定址的對稱性,即傳送和接收程序必須指定對方,以便通訊。這種方案的乙個變形採用定址的非對稱性,即只要傳送者指定接收者,而接收者不需要指定傳送者。採用這種方案,原語 send() 和 receive() 的定義如下:

這兩個方案(對稱和非對稱的定址)的缺點是:生成程序定義的有限模組化。更改程序的識別符號可能需要分析所有其他程序定義。所有舊的識別符號的引用都應找到,以便修改成為新識別符號。通常,任何這樣的硬編碼技術(其中識別符號需要明確指定),與下面所述的採用間接的技術相比要差。在間接通訊中,通過郵箱或埠來傳送和接收訊息。郵箱可以抽象成乙個物件,程序可以向其中存放訊息,也可從中刪除訊息,每個郵箱都有乙個唯一的識別符號。例如,posix 訊息佇列採用乙個整數值來標識乙個郵箱。乙個程序可以通過多個不同郵箱與另乙個程序通訊,但是兩個程序只有擁有乙個共享郵箱時才能通訊。原語 send() 和 receive() 定義如下:

對於這種方案,通訊鏈路具有如下特點:

現在假設程序 p1、p2 和 p3 都共享郵箱 a。程序 p1 傳送乙個訊息到 a,而程序 p2 和 p3 都對 a 執行 receive()。哪個程序會收到 p1 傳送的訊息?

答案取決於所選擇的方案:

郵箱可以為程序或作業系統擁有。如果郵箱為程序擁有(即郵箱是程序位址空間的一部分),那麼需要區分所有者(只能從郵箱接收訊息)和使用者(只能向郵箱傳送訊息)。由於每個郵箱都有唯一的識別符號,所以關於誰能接收發到郵箱的訊息沒有任何疑問。當擁有郵箱的程序終止,那麼郵箱消失。任何程序後來向該郵箱傳送訊息,都會得知郵箱不再存在。與此相反,作業系統擁有的郵箱是獨立存在的;它不屬於某個特定程序。因此,作業系統必須提供機制,以便允許程序進行如下操作:

建立新的郵箱。

通過郵箱傳送和接收訊息。

刪除郵箱。

建立新郵箱的程序預設為郵箱的所有者。開始時,所有者是唯一能通過該郵箱接收訊息的程序。不過,通過系統呼叫,擁有權和接收特權可以傳給其他程序。當然,這樣可以導致每個郵箱具有多個接收者。

同步程序間通訊可以通過呼叫原語 send() 和 receive() 來進行。實現這些原語有不同的設計方案。訊息傳遞可以是阻塞或非阻塞,也稱為同步或非同步:

不同組合的 send() 和 receive() 都有可能。當 send() 和 receive() 都是阻塞的,則在傳送者和接收者之間就有乙個交會。當採用阻塞的 send() 和 receive()時,生產者-消費者問題的解決就簡單了。生產者僅需呼叫阻塞 send() 並且等待,直到訊息被送到接收者或郵箱。同樣,當消費者呼叫 receive() 時,它會阻塞直到有乙個訊息可用。這種情況如下**所示:12

3456

78910

1112

//採用訊息傳遞的生產者程序

message next_produced;

while(true)

//採用訊息佇列的消費者程序

message next_consumed;

while(true)

快取不管通訊是直接的還是間接的,通訊程序交換的訊息總是駐留在臨時佇列中。簡單地講,佇列實現有三種方法:

零容量:佇列的最大長度為 0。因此,鏈路中不能有任何訊息處於等待。對於這種情況,傳送者應阻塞,直到接收者接收到訊息。

有限容量:佇列長度為有限的 n。因此,最多只能有 n 個訊息駐留其中。如果在傳送新訊息時佇列未滿,那麼該訊息可以放在佇列中(或者複製訊息或者儲存訊息的指標),且傳送者可以繼續執行而不必等待。如果鏈路已滿,那麼傳送者應阻塞,直到佇列空間有可用的為止。

無限容量:佇列長度可以無限,因此,不管多少訊息都可在其中等待。傳送者從不阻塞。

零容量情況稱為無緩衝的訊息系統,其他情況稱為自動緩衝的訊息系統。

參考:共享記憶體和訊息佇列原理概述

共享記憶體和訊息佇列原理概述

作業系統內的併發執行程序可以是獨立的也可以是協作的 提供環境允許程序協作,具有許多理由 協作程序需要有一種程序間通訊機制 簡稱 ipc 以允許程序相互交換資料與資訊。程序間通訊有兩種基本模型 共享記憶體和訊息傳遞 訊息佇列 圖 1 給出了這兩種模型的對比。圖 1 通訊模型 上述兩種模型在作業系統中都...

linux 訊息佇列 和 共享記憶體

1.基本知識 存在於核心中2.基本流程及函式 傳送 接收 1 申請key值 2 建立 開啟 訊息佇列 3 傳送訊息 建立結構體 typedef struct msg t 1 key t key ftok 5 if key 0 2 int msgid msgget key,ipc creat 0777...

管道 訊息佇列 共享記憶體

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