Linux管道
管道是Linux中很重要的一種通訊方式,是把一個程式的輸出直接連線到另一個程式的輸入,常說的管道多是指無名管道,無名管道只能用於具有親緣關係的程式之間,這是它與有名管道的最大區別。
有名管道叫named pipe或者FIFO(先進先出),可以用函式mkfifo()建立。
Linux管道的實現機制
在Linux中,管道是一種使用非常頻繁的通訊機制。從本質上說,管道也是一種檔案,但它又和一般的檔案有所不同,管道可以克服使用檔案進行通訊的兩個問題,具體表現為:
· 限制管道的大小。實際上,管道是一個固定大小的緩衝區。在Linux中,該緩衝區的大小為1頁,即4K位元組,使得它的大小不象檔案那樣不加檢驗地增長。使用單個固定緩衝區也會帶來問題,比如在寫管道時可能變滿,當這種情況發生時,隨後對管道的write()呼叫將預設地被阻塞,等待某些資料被讀取,以便騰出足夠的空間供write()呼叫寫。
· 讀取程式也可能工作得比寫程式快。當所有當前程式資料已被讀取時,管道變空。當這種情況發生時,一個隨後的read()呼叫將預設地被阻塞,等待某些資料被寫入,這解決了read()呼叫返回檔案結束的問題。
注意:從管道讀資料是一次性操作,資料一旦被讀,它就從管道中被拋棄,釋放空間以便寫更多的資料。
1. 管道的結構
在 Linux 中,管道的實現並沒有使用專門的資料結構,而是藉助了檔案系統的file結構和VFS的索引節點inode。透過將兩個 file 結構指向同一個臨時的 VFS 索引節點,而這個 VFS 索引節點又指向一個物理頁面而實現的。
2.管道的讀寫
管道實現的原始碼在fs/pipe.c中,在pipe.c中有很多函式,其中有兩個函式比較重要,即管道讀函式pipe_read()和管道寫函式 pipe_wrtie()。管道寫函式透過將位元組複製到 VFS 索引節點指向的實體記憶體而寫入資料,而管道讀函式則透過複製實體記憶體中的位元組而讀出資料。當然,核心必須利用一定的機制同步對管道的訪問,為此,核心使用了鎖、等待佇列和訊號。
當寫程式向管道中寫入時,它利用標準的庫函式write(),系統根據庫函式傳遞的檔案描述符,可找到該檔案的 file 結構。file 結構中指定了用來進行寫操作的函式(即寫入函式)地址,於是,核心呼叫該函式完成寫操作。寫入函式在向記憶體中寫入資料之前,必須首先檢查 VFS 索引節點中的資訊,同時滿足如下條件時,才能進行實際的記憶體複製工作:
·記憶體中有足夠的空間可容納所有要寫入的資料;
·記憶體沒有被讀程式鎖定。
如果同時滿足上述條件,寫入函式首先鎖定記憶體,然後從寫程式的地址空間中複製資料到記憶體。否則,寫入程式就休眠在 VFS 索引節點的等待佇列中,接下來,核心將呼叫排程程式,而排程程式會選擇其他程式執行。寫入程式實際處於可中斷的等待狀態,當記憶體中有足夠的空間可以容納寫入資料,或記憶體被解鎖時,讀取程式會喚醒寫入程式,這時,寫入程式將接收到訊號。當資料寫入記憶體之後,記憶體被解鎖,而所有休眠在索引節點的讀取程式會被喚醒。
管道的讀取過程和寫入過程類似。但是,程式可以在沒有資料或記憶體被鎖定時立即返回錯誤資訊,而不是阻塞該程式,這依賴於檔案或管道的開啟模式。反之,程式可以休眠在索引節點的等待佇列中等待寫入程式寫入資料。當所有的程式完成了管道操作之後,管道的索引節點被丟棄,而共享資料頁也被釋放。
因為管道的實現涉及很多檔案的操作,因此,當讀者學完有關檔案系統的內容後來讀pipe.c中的程式碼,你會覺得並不難理解。
Linux 管道的建立和使用都要簡單一些,唯一的原因是它需要更少的引數。實現與 Windows 相同的管道建立目標,Linux 和 UNIX 使用下面的程式碼片段:
建立 Linux 命名管道
1 2 3 4 5 6 7 8 9 | int fd1[2]; if (pipe(fd1)) { printf ( "pipe() FAILED: errno=%d" , errno ); return 1; } |
Linux 還支援命名管道。對這些數字的早期評論員建議我,為公平起見,應該比較 Linux 的命名管道和 Windows 的命名管道。我寫了另一個在 Linux 上使用命名管道的程式。我發現對於 Linux 上命名的和未命名的管道,結果是沒有區別。
Linux 管道比 Windows 2000 命名管道快很多,而 Windows 2000 命名管道比 Windows XP 命名管道快得多。
例子:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | #include #include int main() { int n,fd[2]; // 這裡的fd是檔案描述符的陣列,用於建立管道做準備的 pid_t pid; char line[100]; if (pipe(fd)<0) // 建立管道 printf ( "pipe create errorn" ); if ((pid=fork())<0) //利用fork()建立新程式 printf ( "fork errorn" ); else if (pid>0){ //這裡是父程式,先關閉管道的讀出端,然後在管道的寫端寫入“hello world" close(fd[0]); write(fd[1], "hello wordn" ,11); } else { close(fd[1]); //這裡是子程式,先關閉管道的寫入端,然後在管道的讀出端讀出資料 n= read(fd[0],line,100); write(STDOUT_FILENO,line,n); } exit (0); } |
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/24790158/viewspace-1044146/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 【linux】管道!!!Linux
- Linux 管道Linux
- [Linux]管道Linux
- Linux管道符Linux
- Linux 之管道Linux
- linux管道詳解Linux
- linux——管道詳解Linux
- 介紹 Linux 中的管道和命名管道Linux
- Linux 命令 管道 緩衝區Linux
- linux 程式間通訊之管道Linux
- Linux 的程式間通訊:管道Linux
- linux9-grep&wc&管道符Linux
- Linux系統程式設計—有名管道Linux程式設計
- Linux的管道機制和重定向Linux
- Linux中重定向和管道介紹Linux
- Linux程式間通訊②:有名管道FIFOLinux
- Linux管道命令是什麼?如何使用?Linux
- linux程式間通訊--管道(PIPE & FIFO)Linux
- Linux系統程式設計之匿名管道Linux程式設計
- Linux中的管道是什麼?管道與共享記憶體的區別有哪些?Linux記憶體
- linux3-管道符、重定向、環境變數Linux變數
- 在Linux中,什麼是管道?它是如何工作的?Linux
- 管道 |
- 在Linux中,什麼是管道操作,以及如何使用它?Linux
- Linux 核心最新高危提權漏洞:髒管道 (Dirty Pipe)Linux
- 在Linux中,管道(pipe)和重定向(redirection)的是什麼?Linux
- 『學了就忘』Linux基礎命令 — 33、管道符的使用Linux
- Linux:管道命令與文字處理三劍客(grep、sed、awk)Linux
- 【linux】系統程式設計-1-程式、管道和訊號Linux程式設計
- angular 管道Angular
- redis管道Redis
- Filter管道Filter
- 演算法鏈與管道(上):建立管道演算法
- Linux-task_struct和檔案系統及管道的關係LinuxStruct
- Linux系統程式設計之程式間通訊方式:管道(二)Linux程式設計
- Linux系統程式設計之程式間通訊方式:管道(一)Linux程式設計
- Linux大檔案重定向和管道的效率對比總結Linux
- Linux 下的程式間通訊:使用管道和訊息佇列Linux佇列
- Linux系統中的管道命令、grep命令、sed命令和awk命令Linux