linux在shell中如何使用緩沖模式的管道fifo

問題的需求

當我們需要把一個程序的輸出重定向到一個管道時,而由另一個程序從管道中讀取這些輸出時,自然想到的是下面辦法:

$ mkfifo  mylog.fifo
$ /path/to/myprogram 1>mylog.fifo 2>&1

這個用法是有問題的:
程序myprogram的運行將會hang在第一個輸出語句,直到mylog.fifo里面的內(nèi)如被取走。換句話說,mylog.fifo的工作方式是阻塞的,即寫操作不會返回,直到寫的內(nèi)容已經(jīng)被讀取為止。

如果用戶能夠保證讀操作能實時健全的運行,不會阻塞對它的寫操作,那么這種模式也是可以工作的。但是這有很大風險,會阻擾主進程的正常功能,聽起來不是很完美。

那么能不能讓fifo有緩沖功能呢,即寫完立刻返回,只要fifo有足夠的buffer沒有被塞滿,而不需要等到被讀取,fifo自動緩沖寫進來的內(nèi)容,聽起來這個需求很合理。

fifo的非阻塞模式

實際上fifo是有非阻塞模式的:

  1. fifo可以工作在阻塞和非阻塞兩種模式。
  2. fifo還可以設(shè)置緩沖區(qū)(buffer)的大小。

這就很完美了,可是google了一番,這些開關(guān)模式只能在API里面通過對文件FD進行設(shè)置,例如open(..., mode),或者fnctl(fd, mode),而我們的使用場景是在shell里面通過重定向,此時fifo的打開和關(guān)閉都是有shell環(huán)境指定的,無法使用API來管理這些FD。

(關(guān)于program API設(shè)置fifo的工作模式,google一下資料很多,這里就不重復(fù)了)

shell模式下的非阻塞模式

目前找到一個辦法是在shell模式下,以READ-WRITE的方式打開fifo,這樣就能讓fifo工作在非阻塞模式(我不知道為什么):

$ exec 3<>/path/to/mylog.fifo

如果不想指定FD,而使用系統(tǒng)分配的FD(在bash 4.2上驗證通過):

$ exec {MYFD}<>/path/to/mylog.fifo
$ echo ${MYFD}

這條命令的功能是以讀寫的方式打開文件/path/to/mylog.fifo,并把fd=3分配這個文件,后面可以用fd=3來對這個文件進行操作。補充一下在linux進程的FD表是可以繼承的,即fork出來的子進程自動復(fù)制父進程的FD表,也就是在在當前shell下面起來的所有子進程都可以使用fd=3這個文件描述符。

這里比較有趣的一點是,F(xiàn)IFO的打開操作不必要和FIFO的使用在同一個進程里面,也不必是父子進程關(guān)系(考慮到子進程自動復(fù)制父進程的FD表);即FIFO的打開操作可以在任何一個SHELL里面,然后FIFO的使用在任意其它SHELL里面。舉例來說,Terminal 1以讀寫方式打開FIFO,然后Terminal 2往FIFO里面寫數(shù)據(jù),最后Terminal 3從FIFO里面讀取數(shù)據(jù),這種情況下Terminal 2的寫操作也是非阻塞的,但是Terminal 1必須保持,不能退出,否則FD會被關(guān)閉;一旦FD關(guān)閉,F(xiàn)IFO又重新變回阻塞方式。

查看當前進程fd列表會看到一條

$ lsof -f -p $$
COMMAND  PID    USER   FD   TYPE DEVICE  SIZE/OFF     NODE NAME
...
bash    2347 <uid>    3u  FIFO  249,0       0t0 51477762 /path/to/mylog.fifo

fd的值是3,指向fifo文件/path/to/mylog.fifo

再來測試用戶程序的讀寫操作

$ /path/to/myprogram 1>/path/to/mylog.fifo 2>&1

或者,直接使用fd,而不是文件名

$ /path/to/myprogram 1>&3 2>&1

此時myprogram就不會被阻塞在第一條output語句上,fifo緩存的輸出的內(nèi)容;不過也要注意不能把fifo的緩沖區(qū)寫滿;如果寫滿了,寫操作會繼續(xù)阻塞,直到fifo緩沖區(qū)釋放出新的空間。

最后我們關(guān)閉fifo對應(yīng)的fs

$ exec 3<&-      # or, exec {MYFD}<&-
$ lsof -f -p $$
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容