bash: パイプ、ティー、プロセス代替の競合条件

bash: パイプ、ティー、プロセス代替の競合条件

twice出力を2回見たいのですが、このスクリプトは一度だけ出力します。

dump() {
    (sleep 1; cat) > "$1"
}
(sleep 0; echo "twice") | tee >(dump "./a.txt")
echo "$(< "a.txt")"

2回視聴するには、睡眠スケジュールを調整する必要がありました。

dump() {
    (sleep 0; cat) > "$1"
}
(sleep 1; echo "twice") | tee >(dump "./a.txt")
echo "$(< "a.txt")"

ここで競合状態の原因は何ですか?

ベストアンサー1

プロセス交換呼び出しはdump非同期プロセスとして実行されます。これはtee、出力がここに書き込まれ、パイプラインが完了したことを意味します。tee作成すると出力がバッファリングされ、パイプが完了します。データ量がパイプバッファサイズを超えています。、使用するのをtee待つ必要があり、元のコードはほとんど機能します。dump

質問で行ったように少量のデータしか書き込めないと仮定すると、a.txtパイプが終了した直後にファイルに何も書き込む機会が生じる前にデータを読み取りますdump(データが保留中の状態でまだバックグラウンドで眠っています)。パイプバッファ)。

エラーコードを実行した後にファイルを見ると、a.txt文字列が含まれていることがわかりますtwice。したがって、sleep 1関数に与えられたわずかな遅延の後、最終的にはその位置に到達します。

パイプが早期にシャットダウンするのを防ぐには、cat最後に次を追加します。

dump() {
    (sleep 1; cat) > "$1"
}

(sleep 0; echo "twice") | tee >(dump "./a.txt") | cat
echo "$(< "a.txt")"

catこれで、プロセスは出力がパイプを介して到着するのを待たなければならないために機能しますdump(そうではありませんが、それはわかりません)。これにより、dump呼び出しが返されるまでパイプのシャットダウンが遅れます。この時点でデータが記録され、a.txtスクリプトの最後のコマンドを使用して取得できます。

パイプラインでプロセスを同期する唯一のものはI / Oです。これは、前のプロセスからデータを読み取り、それを次のプロセスに書き込むことです。プロセスがある時点で前のステップのデータを読み取ろうとすると、読み取るデータがあるか、前のステップでパイプの端を閉じるまでブロックされます。

catデフォルトは標準入力から読み取ることです。追加された標準入力は、catパイプラインの前の段階で標準出力teeと手順の置き換えに接続されます。dumpユーティリティcatは、読み取る内容がなくなるまで読み込みます。これはteeどちらも実行が完了するまでdump発生しません。


コードの整理されたバージョン:

dump() {
    sleep 1
    cat >"$1"
}

echo twice | tee >(dump ./a.txt) | cat

cat a.txt

おすすめ記事