簡単に言うと:
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
開くが完了するまでブロックしfifo
、cat
開始して開き、fifo
ブロックを解除しecho a
てからecho b
実行します。
ただし、ここでの主な要因は、cat
FIFOがオンになっているときです。それまで、シェルブロックはリダイレクトを設定しようとします。表示される出力の順序は、最終的に書き込みプロセスがロック解除される順序に依存します。
最初に実行すると、他の結果が表示されますcat
。
rm fifo; mkfifo fifo; cat fifo & echo a > fifo & echo b > fifo
これはfifo
書き込みオープンをブロックしないため(まだ保証できません)、a
最初は最初の設定よりも頻度が高くなります。cat
事前実行完了も確認できますecho b
。つまり出力のみ可能ですa
。