溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

linux管道的實(shí)現(xiàn)機(jī)制是什么

發(fā)布時(shí)間:2023-02-03 11:29:17 來(lái)源:億速云 閱讀:129 作者:iii 欄目:建站服務(wù)器

今天小編給大家分享一下linux管道的實(shí)現(xiàn)機(jī)制是什么的相關(guān)知識(shí)點(diǎn),內(nèi)容詳細(xì),邏輯清晰,相信大部分人都還太了解這方面的知識(shí),所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來(lái)了解一下吧。

在linux中,管道是一種通信機(jī)制,是把一個(gè)程序的輸出直接連接到另一個(gè)程序的輸入。從本質(zhì)上說(shuō),管道也是一種文件,但它又和一般的文件有所不同,管道可以克服使用文件進(jìn)行通信的兩個(gè)問(wèn)題,具體表現(xiàn)為:限制管道的大小、讀取進(jìn)程可能工作得比寫進(jìn)程快。

管道是Linux中很重要的一種通信方式,是把一個(gè)程序的輸出直接連接到另一個(gè)程序的輸入。常說(shuō)的管道多是指無(wú)名管道,無(wú)名管道只能用于具有親緣關(guān)系的進(jìn)程之間,這是它與有名管道的最大區(qū)別。

有名管道叫named pipe或者FIFO(先進(jìn)先出),可以用函數(shù)mkfifo()創(chuàng)建。

Linux管道的實(shí)現(xiàn)機(jī)制

在Linux中,管道是一種使用非常頻繁的通信機(jī)制。從本質(zhì)上說(shuō),管道也是一種文件,但它又和一般的文件有所不同,管道可以克服使用文件進(jìn)行通信的兩個(gè)問(wèn)題,具體表現(xiàn)為:

  • 限制管道的大小。實(shí)際上,管道是一個(gè)固定大小的緩沖區(qū)。在Linux中,該緩沖區(qū)的大小為1頁(yè),即4K字節(jié),使得它的大小不象文件那樣不加檢驗(yàn)地增長(zhǎng)。使用單個(gè)固定緩沖區(qū)也會(huì)帶來(lái)問(wèn)題,比如在寫管道時(shí)可能變滿,當(dāng)這種情況發(fā)生時(shí),隨后對(duì)管道的write()調(diào)用將默認(rèn)地被阻塞,等待某些數(shù)據(jù)被讀取,以便騰出足夠的空間供write()調(diào)用寫。

  • 讀取進(jìn)程也可能工作得比寫進(jìn)程快。當(dāng)所有當(dāng)前進(jìn)程數(shù)據(jù)已被讀取時(shí),管道變空。當(dāng)這種情況發(fā)生時(shí),一個(gè)隨后的read()調(diào)用將默認(rèn)地被阻塞,等待某些數(shù)據(jù)被寫入,這解決了read()調(diào)用返回文件結(jié)束的問(wèn)題。

注意:從管道讀數(shù)據(jù)是一次性操作,數(shù)據(jù)一旦被讀,它就從管道中被拋棄,釋放空間以便寫更多的數(shù)據(jù)。

1. 管道的結(jié)構(gòu)

在 Linux 中,管道的實(shí)現(xiàn)并沒有使用專門的數(shù)據(jù)結(jié)構(gòu),而是借助了文件系統(tǒng)的file結(jié)構(gòu)和VFS的索引節(jié)點(diǎn)inode。通過(guò)將兩個(gè) file 結(jié)構(gòu)指向同一個(gè)臨時(shí)的 VFS 索引節(jié)點(diǎn),而這個(gè) VFS 索引節(jié)點(diǎn)又指向一個(gè)物理頁(yè)面而實(shí)現(xiàn)的。

2.管道的讀寫

管道實(shí)現(xiàn)的源代碼在fs/pipe.c中,在pipe.c中有很多函數(shù),其中有兩個(gè)函數(shù)比較重要,即管道讀函數(shù)pipe_read()和管道寫函數(shù)pipe_wrtie()。管道寫函數(shù)通過(guò)將字節(jié)復(fù)制到 VFS 索引節(jié)點(diǎn)指向的物理內(nèi)存而寫入數(shù)據(jù),而管道讀函數(shù)則通過(guò)復(fù)制物理內(nèi)存中的字節(jié)而讀出數(shù)據(jù)。當(dāng)然,內(nèi)核必須利用一定的機(jī)制同步對(duì)管道的訪問(wèn),為此,內(nèi)核使用了鎖、等待隊(duì)列和信號(hào)。

當(dāng)寫進(jìn)程向管道中寫入時(shí),它利用標(biāo)準(zhǔn)的庫(kù)函數(shù)write(),系統(tǒng)根據(jù)庫(kù)函數(shù)傳遞的文件描述符,可找到該文件的 file 結(jié)構(gòu)。file 結(jié)構(gòu)中指定了用來(lái)進(jìn)行寫操作的函數(shù)(即寫入函數(shù))地址,于是,內(nèi)核調(diào)用該函數(shù)完成寫操作。寫入函數(shù)在向內(nèi)存中寫入數(shù)據(jù)之前,必須首先檢查 VFS 索引節(jié)點(diǎn)中的信息,同時(shí)滿足如下條件時(shí),才能進(jìn)行實(shí)際的內(nèi)存復(fù)制工作:

  • 內(nèi)存中有足夠的空間可容納所有要寫入的數(shù)據(jù);

  • 內(nèi)存沒有被讀程序鎖定。

如果同時(shí)滿足上述條件,寫入函數(shù)首先鎖定內(nèi)存,然后從寫進(jìn)程的地址空間中復(fù)制數(shù)據(jù)到內(nèi)存。否則,寫入進(jìn)程就休眠在 VFS 索 引節(jié)點(diǎn)的等待隊(duì)列中,接下來(lái),內(nèi)核將調(diào)用調(diào)度程序,而調(diào)度程序會(huì)選擇其他進(jìn)程運(yùn)行。寫入進(jìn)程實(shí)際處于可中斷的等待狀態(tài),當(dāng)內(nèi)存中有足夠的空間可以容納寫入 數(shù)據(jù),或內(nèi)存被解鎖時(shí),讀取進(jìn)程會(huì)喚醒寫入進(jìn)程,這時(shí),寫入進(jìn)程將接收到信號(hào)。當(dāng)數(shù)據(jù)寫入內(nèi)存之后,內(nèi)存被解鎖,而所有休眠在索引節(jié)點(diǎn)的讀取進(jìn)程會(huì)被喚 醒。

管 道的讀取過(guò)程和寫入過(guò)程類似。但是,進(jìn)程可以在沒有數(shù)據(jù)或內(nèi)存被鎖定時(shí)立即返回錯(cuò)誤信息,而不是阻塞該進(jìn)程,這依賴于文件或管道的打開模式。反之,進(jìn)程可 以休眠在索引節(jié)點(diǎn)的等待隊(duì)列中等待寫入進(jìn)程寫入數(shù)據(jù)。當(dāng)所有的進(jìn)程完成了管道操作之后,管道的索引節(jié)點(diǎn)被丟棄,而共享數(shù)據(jù)頁(yè)也被釋放。

因?yàn)楣艿赖膶?shí)現(xiàn)涉及很多文件的操作,因此,當(dāng)讀者學(xué)完有關(guān)文件系統(tǒng)的內(nèi)容后來(lái)讀pipe.c中的代碼,你會(huì)覺得并不難理解。

Linux 管道的創(chuàng)建和使用都要簡(jiǎn)單一些,唯一的原因是它需要更少的參數(shù)。實(shí)現(xiàn)與 Windows 相同的管道創(chuàng)建目標(biāo),Linux 和 UNIX 使用下面的代碼片段:

創(chuàng)建 Linux 命名管道

int fd1[2];
if(pipe(fd1))
{
 printf("pipe() FAILED: errno=%d",errno);
 return 1;
}

Linux 管道對(duì)阻塞之前一次寫操作的大小有限制。 專門為每個(gè)管道所使用的內(nèi)核級(jí)緩沖區(qū)確切為 4096 字節(jié)。 除非閱讀器清空管道,否則一次超過(guò) 4K 的寫操作將被阻塞。 實(shí)際上這算不上什么限制,因?yàn)樽x和寫操作是在不同的線程中實(shí)現(xiàn)的。

Linux 還支持命名管道。對(duì)這些數(shù)字的早期評(píng)論員建議我,為公平起見,應(yīng)該比較 Linux 的命名管道和 Windows 的命名管道。我寫了另一個(gè)在 Linux 上使用命名管道的程序。我發(fā)現(xiàn)對(duì)于 Linux 上命名的和未命名的管道,結(jié)果是沒有區(qū)別。

Linux 管道比 Windows 2000 命名管道快很多,而 Windows 2000 命名管道比 Windows XP 命名管道快得多。

例子:

#include<stdio.h>
#include<unistd.h>


int main()
{
int n,fd[2];                         // 這里的fd是文件描述符的數(shù)組,用于創(chuàng)建管道做準(zhǔn)備的
pid_t pid;
char line[100];
if(pipe(fd)<0)                     //   創(chuàng)建管道
   printf("pipe create error/n");

if((pid=fork())<0)              //利用fork()創(chuàng)建新進(jìn)程
    printf("fork error/n");

else if(pid>0){                   //這里是父進(jìn)程,先關(guān)閉管道的讀出端,然后在管道的寫端寫入“hello world"
    close(fd[0]);
    write(fd[1],"hello word/n",11);
}
else{
    close(fd[1]);                 //這里是子進(jìn)程,先關(guān)閉管道的寫入端,然后在管道的讀出端讀出數(shù)據(jù)
   n= read(fd[0],line,100);
    write(STDOUT_FILENO,line,n);
}
exit(0);
}

以上就是“l(fā)inux管道的實(shí)現(xiàn)機(jī)制是什么”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會(huì)為大家更新不同的知識(shí),如果還想學(xué)習(xí)更多的知識(shí),請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI