作業系統 - 消息傳遞系統中的進程間通信

2020-10-03 吃泡菜的魚

在一文中我們討論了在一個共享內存的環境中進行通訊。這要求了進程間共享一塊內存區域,並且可以讓應用編程人員通過代碼訪問和操縱這塊共享內存。達到相同效果的另一種方法是,作業系統提供用於進程之間通過消息傳遞的工具來實現相互通信的。

消息傳遞提供了一種機制,這種機制允許進程在不分享相同地址空間的情況下,通訊和同步他們的行為。這在分布式系統中特別有用,因為通訊的進程為了連結在網絡中的不同計算機上。比方說,一個網際網路聊天程序被設計用於聊天的參與方與另一方交換信息。

一個消息傳遞機制至少提供兩種操作:

  • send(message) 發送消息
  • receive(message) 接受消息

進程發送的消息的大小可以是固定的,也可以是可變的。如果只能發送固定大小的消息,則系統級實現是直接的。但是,這種限制使編程任務更加困難。相反,可變大小的消息需要更複雜的系統級實現,但編程任務變得更簡單。這是在整個作業系統設計中常見的一種折衷。

如果進程P和Q想到通信,他們必須可以相互發送和接受消息:它們兩個之間必須要有一條通訊鏈路。這個鏈路可以由好幾種方式實現。這裡我們關注的不是鏈路的物理實現而是邏輯上的實現。下下面是幾種邏輯上的實現鏈路的方法。

  • 直接或間接通信
  • 同步或異步通信
  • 自動或顯式緩衝

命名Naming

想要通訊的進程必須要有一種互相指待的方法。他們可以直接或間接通訊。

在直接通訊中,每個想要通訊的進程都必須顯示地對通訊和發送或接受方命名。在這樣的模式下,原本的send和receives會定義如下:

  • send(P, message) - 給進程P發送消息
  • receive(Q, message) - 接受來自進程Q的消息

這樣模式下的通訊鏈路有如下屬性:

  • 每對想要通訊的進程間的鏈路是自動創建的。進程需要互相知道對方的身份以便通信
  • 一條鏈路只與兩個進程相關
  • 在兩個進程之間只存在一條通訊鏈路

該方案在尋址方面表現出對稱性。也就是說,發送方進程和接收方進程都必須命名對方才能進行通信。該方案的變體在尋址中採用不對稱性。在這裡,只有發件人為收件人命名;收件人無需為發件人命名。在這個方案中send()和receive()原語定義如下:

  • send(P, message) - 向進程P發送消息
  • receive(id, message) - 接收來自任何進程的消息。變量id被設置為發生通信的進程的名字。

這兩種方式(對稱和非對稱)的缺點就是限制了進程定義的模塊化程度。更改一個進程的名稱可能必須要檢查其它所有進程的定義。必須要發現所有對原名稱的引用,以便於更換為新名稱。總的來說,任何這樣硬編碼的技術,也是就是說標識符必須顯性陳述的,都不是大家所想要的。

通過非直接通信,消息可以通過mailboxs或ports來發送和接收。一個mailbox可以被認為是一個抽象的目標,在這裡消息可以被進程放入或移除。每個mailbox有一個獨一無二的標識符。比方說,POSIX消息隊列使用一個整數值來標識mailbox。一個進程可以通過不同的mailbox進行通訊,但兩個進程只有共享一個mailbox是才可以通信。在這個方案中send()和receive()原語定義如下:

  • send(A, message) - 發送消息給mailbox A
  • receive(A, message) - 從mailbox A接收消息

在這個方案中,通信鏈路有如下屬性:

  • 只有當進程雙方有一個共享的mailbox時,進程間的鏈路才能被建立
  • 一個鏈路可能關聯不止兩個進程
  • 在每一對通訊進程之間,存在著不同的鏈路,每個鏈路對應著一個mailbox

現在,假定進程P1,P2,P3,共享mailbox A。進程P1發了一個消息給A,P2和P3執行receive()從A那裡接收到消息。哪一個進程會接收到來自P1的消息。答案取決於如下挑選的方法:

  • 允許鏈路只能最多關聯兩個進程
  • 在同一時間,最多只有一個進程執行receive()操作。
  • 允許系統任意挑選一個進程來接受消息(也就是要麼是P2,要麼是P3,但不是都接收消息)。系統哦你會定義一個算法來選擇哪個進程將接收消息(比如說,round robin,進程輪流接收消息)。系統可以向發送者識別接受者。

一個mailbox可以被一個進程或作業系統所擁有。如果mailbox是歸進程所有的,那麼我們把他們區分為owner(只能從mailbox接收消息)和user(只能向mail發送消息)。因為每個mailbox都有一個獨一無二的owner,哪個進程應該接收發送至mailbox的消息就不會有困擾。但一個擁有mailbox的進程終止時,mailbox就沒有了。任何之後發送給mailbox消息的進程必須被告知mailbox不再存在。

相反,一個被作業系統擁有的mailbox有他自己的地址空間。它是獨立並且不附加於任何指定的進程。作業系統然後必須提供一個機制,這個機制允許進程的如下行為:

  • 創建一個新的mailbox
  • 通過這個mailbox發送和接收消息
  • 刪除mailbox

創建mailbox的進程默認是mailbox的owner。一開始,owner只能從這個mailbox接收消息。然而,ownership和接收特權可以通過過適當的系統調用而傳遞出去。當然,這條規定可能會導致每個mailbox裡都有大量的接收者。

同步

進程間的通信可以通過調用原語send()和receive()來發生。對於每個原語的實現有著不同的設計選擇,消息傳遞可以是阻塞或非阻塞的,也被稱為同步和異步。

  • 阻塞發送。發送信息的進程會一直被阻塞知道消息被接收進程或是mailbox接收
  • 非阻塞發送。發送信息的進程發送消息,然後返回繼續其他的操作
  • 阻塞接收。接受者一直阻塞直到收到一條消息
  • 非阻塞接收。接受者要沒收到一條消息,要沒什麼也沒收到

send()和receives()存在著不同形式的組合。當send()和receive()都阻塞時,我們在發送者和接收者之間有一個集合點。當使用阻塞的send()和receive()語句時,生產者-消費者問題的解決方案就變得微不足道了。生產者僅調用阻塞的send()調用,並等待直到消息傳遞到接收者或郵箱。同樣,當使用者調用receive()時,它將阻塞直到有消息可用為止。如下圖所示:

緩衝Buffering

無論通訊是直接還是間接的,通訊的進程的消息交換是位於一個臨時的隊列中的。基本上,這樣的隊列可以有三種方式實現:

  • Zero capacity。隊列的最長長度是零。因此鏈路不能在其中有任何等待的消息。在這樣的情況下。發送者必須阻塞,直到接收者接收走消息。
  • Bounded capacity。隊列是有有限長度的,因此,裡面最多有n個消息。當新的消息發送後,隊列沒有滿時,消息會被放入隊列,且發送者可以不同等待而繼續其他操作。鏈路的容量是有限的,因此,如果鏈路慢了,發送者就必須阻塞直到隊列中有空間空出來了。
  • Unbounded capacity。隊列的長度是無限的,因此會有許多消息在裡面等待。發送者永遠不會阻塞。

zero-capacity有時被指待沒有緩衝的消息系統。其他幾種情況指待帶有自動緩衝的系統。

相關焦點

  • 作業系統 - 進程間通信
    在作業系統中並發的執行進程可以是獨立的進程,也可以是合作進程。如果進程不需要與系統中其他進程共享數據的的進程是獨立的independent。需要與系統中其他進程相互有影響的進程是合作的cooperating。很明顯與其他進程共享數據的任意進程都是一個cooperationg進程。
  • 你未必知道 Linux作業系統進程間通信
    (一)無名管道,它具有幾個特點:  1) 管道是半雙工的,只能支持數據的單向流動;兩進程間需要通信時需要建立起兩個管道;  2) 無名管道使用pipe()函數創建,只能用於父子進程或者兄弟進程之間;  3) 管道對於通信的兩端進程而言,實質上是一種獨立的文件,只存在於內存中;  4) 數據的讀寫操作:一個進程向管道中寫數據,所寫的數據添加在管道緩衝區的尾部
  • 作業系統 - 共享內存系統中的進程間通信
    通過使用共享內存來進程進程間通信需要相互通訊的進程創建一個共享內存區域。一般而言,共享內存的區域位於創建這個共享內存的進程的地址空間中。其他想要使用這個共享內存來通訊的進程把這段地址附加到他們的地址空間中。回想一下,一般來說,作業系統會阻止一個進程訪問另一個進程的內存地址空間。
  • 6種Linux進程間的通信方式
    進程的概念進程是作業系統的概念,每當我們執行一個程序時,對於作業系統來講就創建了一個進程,在這個過程中,伴隨著資源的分配和釋放。可以認為進程是一個程序的一次執行過程。進程通信的概念進程用戶空間是相互獨立的,一般而言是不能相互訪問的。
  • 作業系統 - 客戶端-伺服器系統中的通信
    但是,在這裡,因為我們要處理的進程是在單獨的系統上執行的,所以必須使用基於消息的通信方案來提供遠程服務。與IPC消息相反,在RPC通信中交換的消息結構良好,因此不再僅僅是數據包。每個消息都發送給偵聽遠程系統上埠的RPC守護程序,並且每個消息都包含一個標識符,該標識符指定要執行的功能以及傳遞給該功能的參數。然後按要求執行該功能,並將任何輸出作為單獨的消息發送回請求者。
  • Linux內核-進程間通信組件的實現
    ,進程間通信,虛擬文件系統和網絡接口。Linux內存管理支持虛擬內存,而多餘出的這部分內存就是通過磁碟申請得到的,平時系統只把當前運行的程序塊保留在內存中,其他程序塊則保留在磁碟中。在內存緊缺時,內存管理負責在磁碟和內存間交換程序塊。二、進程管理進程管理主要控制系統進程對CPU的訪問。
  • python核心編程之linux系統進程間通信-Queue
    進程間通信-QueueProcess之間有時需要通信,作業系統提供了很多機制來實現進程間的通信。1.Queue的使用可以使用multiprocessing模塊的Queue實現多進程之間的數據傳遞,Queue本身是一個消息列隊程序,首先用一個小實例來演示一下Queue的工作原理:#coding=utf-8from multiprocessing import Queueq=Queue(3) #初始化一個Queue對象,最多可接收三條put消息
  • Linux進程間通信——消息隊列
    概念什麼是消息隊列?消息隊列亦稱報文隊列,也叫做信箱。是Linux的一種通信機制,這種通信機制傳遞的數據具有某種結構,而不是簡單的字節流。消息隊列的本質其實是一個內核提供的鍊表,內核基於這個鍊表,實現了一個數據結構向消息隊列中寫數據,實際上是向這個數據結構中插入一個新結點;從消息隊列匯總讀數據,實際上是從這個數據結構中刪除一個結點消息隊列提供了一個從一個進程向另外一個進程發送一塊數據的方法消息隊列也有管道一樣的不足,就是每個數據塊的最大長度是有上限的,系統上全體隊列的最大總長度也有一個上限
  • python筆記44:進程間通信機制-消息隊列
    主要內容:小目標:掌握進程間通信方式主要內容:消息隊列一個問題:父子進程之間變量不共享,他們之間如何進行通信?1.消息隊列消息隊列是進程間通信的一種方式,它基於系統提供的機制實現;使用方式:from multiprocessing import Queue方法說明:
  • 作業系統原理之進程管理
    ;執指令 運中止—>被撤銷)獨立性:獨立運和資源調度的基本單位異步性:進程的執時斷時續,何時執、何時暫停都無法預知結構特徵: 進程實體包括用戶正文段、用戶數據段和進程控制塊5、進程控制塊PCB進程控制塊是進程實體的一部分,是作業系統中最重要的數據結構;進程控制塊中記錄作業系統所需要的、用於描述進程及控制進程運所需的全部信息。
  • 作業系統基礎:進程知識筆記(一)
    進程主要是為了解決多道程序批處理系統和分時系統中針對多個並發執行的程序,用來描述系統中執行時動態變化過程。進程屬於自願分配和獨立運行的基本單位。作業系統控制機構功能主要包括:創建一個進程、撤銷一個已完成的進程、改變進程的狀態、實現進程間的通信。
  • 一文詳解作業系統進程管理
    線程間通信的效率會高於進程間通信。一般進程間通信需要內核介入,而同一進程內的線程間共享該進程的內存和文件,不需要調用內核就可以實現通信。5.進程間通信進程間通信目的一般有共享數據,數據傳輸,消息通知,進程控制等。
  • 一篇快速入門作業系統的進程管理
    線程間通信的效率會高於進程間通信。一般進程間通信需要內核介入,而同一進程內的線程間共享該進程的內存和文件,不需要調用內核就可以實現通信。5.進程間通信進程間通信目的一般有共享數據,數據傳輸,消息通知,進程控制等。
  • 進程間的五種通信方式介紹
    進程間通信又叫IPC (InterProcess Communication)是指在不同進程之間傳播或交換信息。IPC的方式通常有管道(包括無名管道和命名管道)、消息隊列、信號量、共享存儲、Socket。 Socket支持不同主機上的兩個進程IPC。
  • linux環境高級編程-高級IO和進程間通信詳解
    進程間通信介紹了基本進程間通信機制,包括兩大類:進程間數據共享:管道,FIFO,消息隊列和共享存儲進程間數據同步:信號量網絡進程間通信介紹網絡間的進程通信機制:套接字。高級進程間通信高級進程間通信提供一種可以在進程間傳遞文件描述符的機制,包括STREAMS管道和unix域套接字需要C/C++ Linux伺服器架構師學習資料後臺私信「資料」(資料包括C/C++,Linux,
  • Linux後臺伺服器開發——Linux下進程間通信的方式有哪些?
    Linux下進程間通信的方式有:管道消息隊列信號信號量共享存儲套接字一、管道管道是半雙工的,數據只能向一個方向流動;需要雙方通信時,需要建立起兩個管道>消息隊列是消息的連結表,存儲在內核中,由消息隊列標識符標識特點總結:消息隊列是消息的鍊表,具有特定的格式,存放在內存中並由消息隊列標識符標識消息隊列允許一個或多個進程向它寫入與讀取消息管道和消息隊列的通信數據都是先進先出的原則消息隊列可以實現消息的隨機查詢
  • 讓進程間通信更容易 - Pandora.js 的 IPC-Hub
    我們在淘寶業務中也是這樣實踐的,有一個問題也越發明顯,進程間如何通信呢?起初我們有一個比較簡單的 IPC 實現,通過 Domain Socket 進行通信。也是傳統的 C/S 架構的,兩個進程間進行比較基礎的消息通信(比較類似 Node-IPC 這個包)。不過實在是太基礎了,時不時地在想:在同一臺計算機上的同一個語言,為什麼要搞得這麼痛苦?
  • 作業系統 - 系統調用
    參數也可以被程序放在或壓入棧中並且被作業系統彈出。一些作業系統更喜歡塊或棧的方式,因為這樣的方式不會限制傳遞參數的長度數量。另外,作業系統保留有關其所有進程的信息,並且系統調用用於訪問此信息。通常,調用還用於獲取和設置進程信息(get_process_attribute()和set_process_attribute())。通信進程間通信有兩種常見的模型:消息傳遞模型和共享內存模型。
  • 作業系統 - 對進程的操作
    一個子進程可以從作業系統直接獲取資源,或者可以被限制為父進程資源的一個子集。父進程可以把資源分片給子進程,或者也可以在子進程間共享資源(比如共享內存或文件)。將子進程限制為父級資源的子集可防止任何進程通過創建太多子進程而使系統超載。除了提供各種物理和邏輯上的資源,父進程也可以傳遞初始化數據給子進程。比方說,如果一個進程的功能是展示文件的內容在屏幕或終端上,比如說hw1.c。
  • 基於VxWorks的全IP開發平臺進程通信處理機制
    模塊主要實現相同處理器內和不同處理器之間進程間通信功能,進程間的通信主要依靠調度任務從郵箱中接收消息,並把消息派發到各個進程的消息隊列來實現,底層協議類型包括可靠通信協議(TCP)和不可靠通信協議(UDP)。關鍵詞:嵌入式作業系統;網絡處理器單元;消息隊列;Vxworks引言 隨著IP技術的迅速發展,「Everything over IP」的觀念已深入人心。