作為Linux應用程序的開發(fā)人員,對Linux的進程間通信方式肯定是了如指掌,平時的開發(fā)中應該會大量的使用到。當你迅速的在鍵盤上按下【CTRL+C】終止掉一個正在運行中的命令時,你有沒有仔細的思考過背后的原理呢?或者是他們是通過什么通信方式呢?這個通信方式是怎樣實現(xiàn)的呢?本文就帶著大家去Linux進程間通信一探究竟,找出他們的原理。 概念我們都知道,應用程序在運行起來之后(進程),是相互獨立的,都有自己的進程地址空間。但是往往在一些業(yè)務上需要進程間的通信,來完成系統(tǒng)的某個完整的功能。我們來看下進程間通信能干那些事情?首先當然最重要的是:
通信方式進程間的通信方式一般可以分為八種,如下: 他們在不同的標準都有不同的實現(xiàn),如下圖所示: 我們先從管道開始講起來吧。 管道這里說的管理特指的是無名管道,它是一種半雙工的通信方式。也就是說數(shù)據(jù)只能單向流動,一般是在具有親緣關系的進程間使用,比如父子進程。當一個進程創(chuàng)建了一個管道,并調(diào)用fork創(chuàng)建自己的一個子進程后,父進程關閉讀管道端,子進程關閉寫管道端,這樣提供了兩個進程之間數(shù)據(jù)流動的一種方式。 管道是怎么通信的呢? 首先管道是內(nèi)核的一個緩沖區(qū),而且是在內(nèi)存中。管道一頭連接著一個進程的輸出,另一頭連接著另一個進程的輸入。一個緩沖區(qū)不需要很大,它被設計成為環(huán)形的數(shù)據(jù)結(jié)構,以便管道可以被循環(huán)利用。當管道中沒有信息的話,從管道中讀取的進程會等待,直到另一端的進程放入信息。當管道被放滿信息的時候,嘗試放入信息的進程會等待,直到另一端的進程取出信息。當兩個進程都終結(jié)的時候,管道也自動消失。看下圖: 那管道怎樣建立的呢? 從原理上,管道利用fork機制建立,從而讓兩個進程可以連接到同一個PIPE上。最開始的時候,上面的兩個箭頭都連接在同一個進程1上(連接在進程1上的兩個箭頭),如下圖。當fork復制進程的時候,會將這兩個連接也復制到新的進程(進程2)。隨后,每個進程關閉自己不需要的一個連接 (兩個黑色的箭頭被關閉; 進程1關閉從PIPE來的輸入連接,進程2關閉輸出到PIPE的連接),這樣,剩下的紅色連接就構成了如上圖的PIPE。 管道在內(nèi)核中具體怎么實現(xiàn)的呢? 在Linux內(nèi)核中,并沒有針對管道新增數(shù)據(jù)結(jié)構。而是巧妙的借用了文件系統(tǒng)的file結(jié)構和虛擬文件系統(tǒng)的索引節(jié)點inode。通過將兩個 file 結(jié)構指向同一個臨時的 VFS 索引節(jié)點,而這個 VFS 索引節(jié)點又指向一個物理頁面而實現(xiàn)的。 具體實現(xiàn) 管道的實現(xiàn)其實也不難,源代碼在內(nèi)核工程中的fs/pipe.c,我們著重的講兩個比較重要的接口吧,也就是常用的pipe_read()和pipe_write(),前者是管道讀函數(shù),后者是管道寫函數(shù)。 管道寫函數(shù)將字節(jié)數(shù)據(jù)復制到虛擬文件系統(tǒng)索引節(jié)點指向的物理內(nèi)存頁,而讀函數(shù)則是相反:讀出數(shù)據(jù)。當然這里存在著競爭的管理,需要一定的同步機制,使用鎖,等待隊列和信號。 當我們寫的時候,調(diào)用write(),內(nèi)核根據(jù)傳入的文件描述符fd,找到該文件的file結(jié)構。然后執(zhí)行結(jié)構中f_op中的寫函數(shù)。寫函數(shù)在向內(nèi)存寫入數(shù)據(jù)之前,必須首先檢查虛擬文件系統(tǒng)索引節(jié)點信息,檢查是否有足夠的內(nèi)存空間可以寫和內(nèi)存沒有被讀程序鎖定這兩個條件,只有滿足了,才真正的進行內(nèi)存拷貝。 接下來寫函數(shù)就會鎖定內(nèi)存,然后復制數(shù)據(jù)到內(nèi)存,否則就在虛擬文件系統(tǒng)inode的等待隊列中。 管道的讀取過程和寫入過程類似。但是,進程可以在沒有數(shù)據(jù)或內(nèi)存被鎖定時立即返回錯誤信息,而不是阻塞該進程,這依賴于文件或管道的打開模式。反之,進程可以休眠在索引節(jié)點的等待隊列中等待寫入進程寫入數(shù)據(jù)。當所有的進程完成了管道操作之后,管道的索引節(jié)點被丟棄,而共享數(shù)據(jù)頁也被釋放。 總結(jié)由于篇幅的限制,八大進程間通信只講了管道,文章開頭的疑問也只能等到后續(xù)文章了,也算是留個懸念吧。未完待續(xù).... 覺得不錯,記得點贊轉(zhuǎn)發(fā),關注我! |
|