Linux

Linux 命名管道:不像想像的那樣先進先出

  • January 6, 2022

簡而言之:

mkfifo fifo; (echo a > fifo) &; (echo b > fifo) &; cat fifo

我所期望的:

a
b

因為第一個echo … > fifo應該是第一個打開文件的,所以我希望該程序是第一個寫入它的程序(首先打開它的解鎖)。

我得到什麼:

b
a

令我驚訝的是,當打開兩個單獨的終端以在絕對獨立的程序中進行寫入時,也會發生這種行為。

我是否誤解了命名管道的先進先出語義?

斯蒂芬建議添加延遲:

#!/usr/bin/zsh
delay=$1
N=$(( $2 - 1 ))
out=$(for n in {00..$N}; do
 mkfifo /tmp/fifo$n
 (echo $n > /tmp/fifo$n) &
 sleep $delay
 (echo $(( $n + 1000 )) > /tmp/fifo$n )&
 # intentionally using `cat` here to not step into any smartness
 cat /tmp/fifo$n | sort -C || echo +1
 rm /tmp/fifo$n
done)
echo "$(( $res )) inverted out of $(( $N + 1 ))"

現在,這 100% 正確(delay = 0.1, N = 100)。

儘管如此,mkfifo fifo; (echo a > fifo) &; sleep 0.1 ; (echo b > fifo) &; cat fifo手動執行幾乎總是會產生相反的順序。

事實上,即使複製和粘貼for循環本身也有一半的時間會失敗。我對這裡發生的事情感到非常困惑。

這與管道的 FIFO 語義無關,也無法證明它們的任何內容。這與 FIFO 在打開時阻塞直到它們被打開以進行寫入和讀取的事實有關。cat所以在打開fifo閱讀之前什麼都不會發生。

因為第一個echo應該是第一個。

在後台啟動程序意味著您不知道它們何時實際被調度,因此不能保證第一個後台程序會在第二個後台程序之前完成它的工作。這同樣適用於解除阻塞程序

您可以通過人為地延遲第二個程序來提高機率,同時仍然使用後台程序:

rm fifo; mkfifo fifo; echo a > fifo & (sleep 0.1; echo b > fifo) & cat fifo

延遲時間越長,機率越大:echo a > fifo等待完成打開的塊fifocat啟動並打開fifo哪些解鎖echo a,然後echo b執行。

然而,這裡的主要因素是何時cat打開 FIFO:在此之前,shell 會阻止嘗試設置重定向。最終看到的輸出順序取決於寫入過程被暢通的順序。

如果你cat先執行,你會得到不同的結果:

rm fifo; mkfifo fifo; cat fifo & echo a > fifo & echo b > fifo

這樣一來,fifo寫作的開放往往不會阻塞(仍然,沒有保證),所以你會首先看到a比第一次設置更高的頻率。您還將看到執行cat前完成,僅輸出。echo b``a

引用自:https://unix.stackexchange.com/questions/685305