轉載html
管道
管道是進程間通訊的主要手段之一。一個管道實際上就是個只存在於內存中的文件,
對這個文件的操做要經過兩個已經打開文件進行,它們分別表明管道的兩端。
管道是一種特殊的文件,它不屬於某一種文件系統,而是一種獨立的文件系統,有其本身的數據結構。
根據管道的適用範圍將其分爲:無名管道和命名管道。node
無名管道
主要用於父進程與子進程之間,或者兩個兄弟進程之間。在linux系統中能夠經過系統調用創建起一個單向的通訊管道,且這種關係只能由父進程來創建。linux
命名管道
命名管道是創建在實際的磁盤介質或文件系統(而不是隻存在於內存中)上有本身名字的文件,任何進程能夠在任什麼時候間經過文件名或路徑名與該文件創建聯繫。爲了實現命名管道,引入了一種新的文件類型——FIFO文件(遵循先進先出的原則)。
實現一個命名管道實際上就是實現一個FIFO文件。命名管道一旦創建,以後它的讀、寫以及關閉操做都與普通管道徹底相同。雖然FIFO文件的inode節點在磁盤上,可是僅是一個節點而已,文件的數據仍是存在於內存緩衝頁面中,和普通管道相同。數據結構
管道實現機制
管道是由內核管理的一個緩衝區,至關於咱們放入內存中的一個紙條。
管道的一端鏈接一個進程的輸出。這個進程會向管道中放入信息。
管道的另外一端鏈接一個進程的輸入,這個進程取出被放入管道的信息。
一個緩衝區不須要很大通常爲4K大小,它被設計成爲環形的數據結構,以便管道能夠被循環利用。
當管道中沒有信息的話,從管道中讀取的進程會等待,直到另外一端的進程放入信息。
當管道被放滿信息的時候,嘗試放入信息的進程會等待,直到另外一端的進程取出信息。
當兩個進程都終結的時候,管道也自動消失。函數
建立過程
細節
在Linux中,管道的實現並無使用專門的數據結構,而是藉助了文件系統的file結構和VFS的索引節點inode。
經過將兩個file結構指向同一個臨時的 VFS 索引節點,而這個 VFS 索引節點又指向一個物理頁面而實現的。
以下圖有兩個 file 數據結構,但它們定義文件操做例程地址是不一樣的,其中一個是向管道中寫入數據的例程地址,
而另外一個是從管道中讀出數據的例程地址。
這樣,用戶程序的系統調用仍然是一般的文件操做,而內核卻利用這種抽象機制實現了管道這一特殊操做。spa
讀寫操做
管道實現的源代碼在fs/pipe.c中,在pipe.c中有不少函數,其中有兩個函數比較重要,
即管道讀函數pipe_read()和管道寫函數pipe_wrtie()。
管道寫函數經過將字節複製到 VFS 索引節點指向的物理內存而寫入數據,而管道讀函數則經過複製物理內存中的字節而讀出數據。
固然,內核必須利用必定的機制同步對管道的訪問,爲此,內核使用了鎖、等待隊列和信號。設計
當寫進程向管道中寫入時,它利用標準的庫函數write(),系統根據庫函數傳遞的文件描述符,可找到該文件的 file 結構。
file 結構中指定了用來進行寫操做的函數(即寫入函數)地址,因而,內核調用該函數完成寫操做。
寫入函數在向內存中寫入數據以前,必須首先檢查 VFS 索引節點中的信息,同時知足以下條件時,才能進行實際的內存複製工做:code
內存中有足夠的空間可容納全部要寫入的數據; 內存沒有被讀程序鎖定。
若是同時知足上述條件,寫入函數首先鎖定內存,而後從寫進程的地址空間中複製數據到內存。
不然,寫入進程就休眠在 VFS 索引節點的等待隊列中,接下來,內核將調用調度程序,而調度程序會選擇其餘進程運行。
寫入進程實際處於可中斷的等待狀態,當內存中有足夠的空間能夠容納寫入數據,
或內存被解鎖時,讀取進程會喚醒寫入進程,這時,寫入進程將接收到信號。
當數據寫入內存以後,內存被解鎖,而全部休眠在索引節點的讀取進程會被喚醒。htm
管道的讀取過程和寫入過程相似。可是,進程能夠在沒有數據或內存被鎖定時當即返回錯誤信息,而不是阻塞該進程,
這依賴於文件或管道的打開模式。反之,進程能夠休眠在索引節點的等待隊列中等待寫入進程寫入數據。
當全部的進程完成了管道操做以後,管道的索引節點被丟棄,而共享數據頁也被釋放blog