2

次のコードを使用します。

rm -f pipe
mkfifo pipe

foo () {
    echo 1
    sleep 1
    echo 2
}

#1
exec 3< <(foo &)
cat <&3 # works

#2
foo >pipe &
cat <pipe # works

#3
exec 3<>pipe
foo >&3 &
cat <&3 # hangs

#4 -- update: this is the correct approach for what I want to do
foo >pipe &
exec 3<pipe
rm pipe
cat <&3 # works

アプローチ #3 がハングするのに、他のアプローチはハングしないのはなぜですか? アプローチ #3 をハングさせない方法はありますか?

理論的根拠: 準無名パイプを使用して、非同期で実行されているいくつかのサブプロセスを接続したいので、ファイル記述子がそれを指すようにした後、パイプを削除する必要があります。

mkfifo pipe
exec {fd}<>pipe
rm pipe
# use &$fd only
4

1 に答える 1

2

アプローチ 3 の問題は、FIFOpipeに 2 つのライターがあることです。bash スクリプト ( を使用して読み取り/書き込みで開いたためexec 3<>) と、実行中のサブシェルfooです。すべてのライターがファイル記述子を閉じたときに EOF を読み取ります。1 つのライター ( を実行しているサブシェルfoo) はかなり迅速に (約 1 秒後) 終了するため、ファイル記述子を閉じます。ただし、他のライター(メインシェル)は、ファイル記述子のクローズがどこにもないため、終了するときにのみファイル記述子をクローズします3。ただし、 が最初に終了するのを待っているため、終了できませんcat。それはデッドロックです:

  • catEOFを待っています
  • EOF は、メイン シェルが fd を閉じる (または終了する) ときにのみ表示されます。
  • catメインシェルは終了を待っています

したがって、あなたは決して出ることはありません。

ケース 2 が機能するのは、パイプには 1 つのライター (実行中のサブシェル) しかなく、foo非常に迅速に終了するため、EOF が読み取られるためです。ケース 1 では、fd 3 を読み取り専用で開いているため ( )、ライターは 1 つしかありませんexec 3<

編集:ケース4が正しくないというナンセンスを削除します(コメントを参照)。リーダーがまだ開いていないときにファイルを開くときにもブロックされるため、リーダーが接続する前にライターを終了できないため、それは正しいです。新しく追加されたケース 4 は、残念ながら正しくありません。それは際どいものであり、実行foo前に終了しない (またはパイプを閉じる)場合にのみ機能しexec 3<pipeます。

fifo(7)man ページも確認してください。

カーネルは、少なくとも 1 つのプロセスによって開かれた FIFO 特殊ファイルごとに 1 つのパイプ オブジェクトを保持します。データを渡す前に、FIFO を両端 (読み取りと書き込み) で開く必要があります。通常、もう一方の端も開くまで、FIFO ブロックを開きます。

于 2015-10-15T23:02:50.073 に答える