Linux 名前付きパイプ: 思ったほど先入選出ではない

Linux 名前付きパイプ: 思ったほど先入選出ではない

簡単に言うと:

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

私が期待したもの:

a
b

最初のプロセスはecho … > fifoファイルを開く最初のプロセスである必要があるため、そのプロセスがファイルに書き込む最初のプロセスになりたい(最初に開いてロック解除)。

私が得るもの:

b
a

驚くべきことに、この動作は、完全に別々のプロセスに書き込むために2つの別々の端末を開くときにも発生します。

名前付きパイプの先入れ先出しの意味を誤って理解しているのでしょうか?

Stephenは遅延の追加を提案した。

#!/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ループ自体も半分ほど失敗します。はい非常にここで何が起こっているのか混乱しています。

ベストアンサー1

これは、パイプのFIFOセマンティクスとは何の関係もなく、いかなる方法でもパイプについて何も証明しません。これは、FIFOが書き込みおよび読み取りのために開くまでブロックされるため、読み取りのcatために開くfifoまで何も起こらないという事実に関連しています。

最初のものがecho最初のものでなければならないからです。

バックグラウンドでプロセスを開始することは、そのプロセスが実際にいつ予約されたかを知ることができないことを意味します。約束はありません。最初のバックグラウンドプロセスは、2番目のバックグラウンドプロセスの前にタスクを完了します。同じように適用されますプロセスのブロック解除

バックグラウンドプロセスを引き続き使用しながら、2番目のプロセスを人為的に遅らせることで確率を上げることができます。

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

遅延時間が長くなるほど機会は大きくなります。echo a > fifo開くが完了するまでブロックしfifocat開始して開き、fifoブロックを解除しecho aてからecho b実行します。

ただし、ここでの主な要因は、catFIFOがオンになっているときです。それまで、シェルブロックはリダイレクトを設定しようとします。表示される出力の順序は、最終的に書き込みプロセスがロック解除される順序に依存します。

最初に実行すると、他の結果が表示されますcat

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

これはfifo書き込みオープンをブロックしないため(まだ保証できません)、a最初は最初の設定よりも頻度が高くなります。cat事前実行完了も確認できますecho bつまり出力のみ可能ですa

おすすめ記事