Linux處理序間通訊Linux進程基礎Linux從程式到進程

來源:互聯網
上載者:User

作者:Vamei 出處:http://www.cnblogs.com/vamei 歡迎轉載,也請保留這段聲明。謝謝!

謝謝nonoob錯誤修正

 

我們在Linux訊號基礎中已經說明,訊號可以看作一種粗糙的處理序間通訊(IPC, interprocess communication)的方式,用以向進程封閉的記憶體空間傳遞資訊。為了讓進程間傳遞更多的資訊量,我們需要其他的處理序間通訊方式。這些處理序間通訊方式可以分為兩種:

  • 管道(PIPE)機制。在Linux文字資料流中,我們提到可以使用管道將一個進程的輸出和另一個進程的輸入串連起來,從而利用檔案操作API來管理處理序間通訊。在shell中,我們經常利用管道將多個進程串連在一起,從而讓各個進程協作,實現複雜的功能。
  • 傳統IPC (interprocess communication)。我們主要是指訊息佇列(message queue),訊號量(semaphore),共用記憶體(shared memory)。這些IPC的特點是允許多進程之間共用資源,這與多線程共用heap和global data相類似。由於多進程任務具有並發性 (每個進程包含一個進程,多個進程的話就有多個線程),所以在共用資源的時候也必須解決同步的問題 (參考Linux多線程與同步)。

 

1. 管道與FIFO檔案

一個原始的IPC方式是所有的進程通過一個檔案交流。比如我在紙(檔案)上寫下我的名字和年紀。另一個人讀這張紙,會知道我的名字和年紀。他也可以在同一張紙上寫下他的資訊,而當我讀這張紙的話,同樣也可以知道別人的資訊。但是,由於硬碟讀寫比較慢,所以這個方式效率很低。那麼,我們是否可以將這張紙放入記憶體中以提高讀寫速度呢?

在Linux文字資料流中,我們已經講解了如何在shell中使用管道串連多個進程。同樣,許多程式設計語言中,也有一些命令用以實作類別似的機制,比如在Python子進程中使用Popen和PIPE,在C語言中也有popen庫函數來實現管道 (shell中的管道就是根據此編寫的)。管道是由核心管理的一個緩衝區(burrer),相當於我們放入記憶體中的一個紙條。管道的一端串連一個進程的輸出。這個進程會向管道中放入資訊。管道的另一端串連一個進程的輸入,這個進程取出被放入管道的資訊。一個緩衝區不需要很大,它被設計成為環形的資料結構,以便管道可以被迴圈利用。當管道中沒有資訊的話,從管道中讀取的進程會等待,直到另一端的進程放入資訊。當管道被放滿資訊的時候,嘗試放入資訊的進程會等待,直到另一端的進程取出資訊。當兩個進程都終結的時候,管道也自動消失。

從原理上,管道利用fork機制建立(參考Linux進程基礎和Linux從程式到進程),從而讓兩個進程可以串連到同一個PIPE上。最開始的時候,上面的兩個箭頭都串連在同一個進程Process 1上(串連在Process 1上的兩個箭頭)。當fork複製進程的時候,會將這兩個串連也複製到新的進程(Process 2)。隨後,每個進程關閉自己不需要的一個串連 (兩個黑色的箭頭被關閉; Process 1關閉從PIPE來的輸入串連,Process 2關閉輸出到PIPE的串連),這樣,剩下的紅色串連就構成了如的PIPE。

由於基於fork機制,所以管道只能用於父進程和子進程之間,或者擁有相同祖先的兩個子進程之間 (有親緣關係的進程之間)。為瞭解決這一問題,Linux提供了FIFO方式串連進程。FIFO又叫做具名管道(named PIPE)。

FIFO (First in, First out)為一種特殊的檔案類型,它在檔案系統中有對應的路徑。當一個進程以讀(r)的方式開啟該檔案,而另一個進程以寫(w)的方式開啟該檔案,那麼核心就會在這兩個進程之間建立管道,所以FIFO實際上也由核心管理,不與硬碟打交道。之所以叫FIFO,是因為管道本質上是一個先進先出的隊列資料結構,最早放入的資料被最先讀出來(好像是傳送帶,一頭放貨,一頭取貨),從而保證資訊交流的順序。FIFO只是借用了檔案系統(file system, 參考Linux檔案管理背景知識)來為管道命名。寫入模式的進程向FIFO檔案中寫入,而讀模式的進程從FIFO檔案中讀出。當刪除FIFO檔案時,管道串連也隨之消失。FIFO的好處在於我們可以通過檔案的路徑來識別管道,從而讓沒有親緣關係的進程之間建立串連。

 

2. 傳統IPC

這幾種傳統IPC實際上有很悠久的曆史,所以其實現方式也並不完善 (比如說我們需要某個進程負責刪除建立的IPC)。一個共同的特徵是它們並不使用檔案操作的API。對於任何一種IPC來說,你都可以建立多個串連,並使用索引值(key)作為識別的方式。我們可以在一個進程中中通過索引值來使用的想要那一個串連 (比如多個訊息佇列,而我們選擇使用其中的一個)。索引值可以通過某種IPC方式在進程間傳遞(比如說我們上面說的PIPE,FIFO或者寫入檔案),也可以在編程的時候內建於程式中。

在幾個進程共用索引值的情況下,這些傳統IPC非常類似於多線程共用資源的方式(參看Linux多線程與同步):

  • semaphore與mutex類似,用於處理同步問題。我們說mutex像是一個只能容納一個人的洗手間,那麼semaphore就像是一個能容納N個人的洗手間。其實從意義上來說,semaphore就是一個計數鎖(我覺得將semaphore翻譯成為訊號量非常容易讓人混淆semaphore與signal),它允許被N個進程獲得。當有更多的進程嘗試獲得semaphore的時候,就必須等待有前面的進程釋放鎖。當N等於1的時候,semaphore與mutex實現的功能就完全相同。許多程式設計語言也使用semaphore處理多線程同步的問題。一個semaphore會一直存在在核心中,直到某個進程刪除它。
  • 共用記憶體與多線程共用global data和heap類似。一個進程可以將自己記憶體空間中的一部分拿出來,允許其它進程讀寫。當使用共用記憶體的時候,我們要注意同步的問題。我們可以使用semaphore同步,也可以在共用記憶體中建立mutex或其它的線程同步變數來同步。由於共用記憶體允許多個進程直接對同一個記憶體地區直接操作,所以它是效率最高的IPC方式。

訊息佇列(message queue)與PIPE相類似。它也是建立一個隊列,先放入隊列的訊息被最先取出。不同的是,訊息佇列允許多個進程放入訊息,也允許多個進程取出訊息。每個訊息可以帶有一個整數識別符(message_type)。你可以通過識別符對訊息分類 (極端的情況是將每個訊息設定一個不同的識別符)。某個進程從隊列中取出訊息的時候,可以按照先進先出的順序取出,也可以只取出符合某個識別符的訊息(有多個這樣的訊息時,同樣按照先進先出的順序取出)。訊息佇列與PIPE的另一個不同在於它並不使用檔案API。最後,一個隊列不會自動消失,它會一直存在於核心中,直到某個進程刪除該隊列。

 

多進程協作可以協助我們充分利用多核和網路時代帶來的優勢。多進程可以有效解決計算瓶頸的問題。互連網通訊實際上也是一個處理序間通訊的問題,只不過這多個進程分佈於不同的電腦上。網路連接是通過socket實現的。由於socket內容龐大,所以我們不在這裡深入。一個小小的註解是,socket也可以用於電腦內部進程間的通訊。

 

總結:

PIPE, FIFO

semaphore, message queue, shared memory; key

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.