您好,登錄后才能下訂單哦!
今天小編給大家分享一下linux管道的實現機制是什么的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
在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 命名管道
int fd1[2];
if(pipe(fd1))
{
printf("pipe() FAILED: errno=%d",errno);
return 1;
}
Linux 管道對阻塞之前一次寫操作的大小有限制。 專門為每個管道所使用的內核級緩沖區確切為 4096 字節。 除非閱讀器清空管道,否則一次超過 4K 的寫操作將被阻塞。 實際上這算不上什么限制,因為讀和寫操作是在不同的線程中實現的。
Linux 還支持命名管道。對這些數字的早期評論員建議我,為公平起見,應該比較 Linux 的命名管道和 Windows 的命名管道。我寫了另一個在 Linux 上使用命名管道的程序。我發現對于 Linux 上命名的和未命名的管道,結果是沒有區別。
Linux 管道比 Windows 2000 命名管道快很多,而 Windows 2000 命名管道比 Windows XP 命名管道快得多。
例子:
#include<stdio.h>
#include<unistd.h>
int main()
{
int n,fd[2]; // 這里的fd是文件描述符的數組,用于創建管道做準備的
pid_t pid;
char line[100];
if(pipe(fd)<0) // 創建管道
printf("pipe create error/n");
if((pid=fork())<0) //利用fork()創建新進程
printf("fork error/n");
else if(pid>0){ //這里是父進程,先關閉管道的讀出端,然后在管道的寫端寫入“hello world"
close(fd[0]);
write(fd[1],"hello word/n",11);
}
else{
close(fd[1]); //這里是子進程,先關閉管道的寫入端,然后在管道的讀出端讀出數據
n= read(fd[0],line,100);
write(STDOUT_FILENO,line,n);
}
exit(0);
}
以上就是“linux管道的實現機制是什么”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。