名前のないパイプを作成するときに2つのファイル記述子が必要なのはなぜですか?

名前のないパイプを作成するときに2つのファイル記述子が必要なのはなぜですか?

私は名前のないパイプについて読みましたが、私が理解したように、パイプはメモリ内のバッファとして実装されています。パイプを作成するときは、バッファ(ファイル記述子)への2つのポインタを返すサイズ2の配列を渡す必要があります。インデックス0はパイプからの読み出しに使用され、インデックス1は書き込みに使用されます。

私の質問は、バッファが1つだけで、両方のインデックスが同じメモリ位置を指し、両方のプロセスが同時に読み書きできない場合、2つのファイル記述子が必要なのはなぜですか?私の質問に意味があることを願っています。

答え1

@MelBoyceが彼のコメントで述べたように、これはパイプの概念的な性質によるものです。これには入力と出力があり、入力に書き込まれた順序とまったく同じ順序で出力からバイトを読み取ります。パイプは一般的なファイルやポインタではないため、パイプ内のどこでも読み書きできません。パイプに入る最初の未読バイトを強制的に読み取る必要があります。

パイプはメモリ内のバッファとして実装することができますが、将来より効率的な他の方法が開発された場合、実装は異なる可能性があります。ただし、パイプラインの概念的な特性は変わりません。それでも同じシステムコールを使用しread(2)write(2)同じように動作します。呼び出されたときに得られたファイル記述子は、pipe(2)パイプを正しく使用するように強制するために使用されます(追加でいくつかのアクセス制御を提供します)。これにより、将来の実装修正によってコードが破損することはありません。

答え2

読み取りと書き込みのための単一のファイル記述子が返された場合、重要な機能はありませんpipe。つまり、EOF信号は発生しません。

パイプの場合、fdを読み取ると、fdが書き込まれた最後のコピーが閉じられたときにEOFが表示されます。仮想シングルFDパイプラインの場合、ソケットと同様に追加のシステムコールが必要ですshutdownが、パイプラインに適用されます。 (パイプはソケットより古く、shutdownソケットの前に存在しなかったことを覚えておいてください。)

pipe_shutdown()このシステムコールを呼び出す責任は誰にありますか?次のようにすると仮定してください。

grep foo /etc/passwd | head

fdが1つだけで、grep両方headが継承されている場合は、grep終了時にheadEOFを受け取る必要があります。ただし、プロセスが保持しているfdheadは書き込み可能であるため、カーネルはパイプに書き込むかどうかはわかりません。プロセスの終了は、プロセスが保持するすべてのパイプfdに自動的にEOFを送信する必要があると考えることもできます。しかし、これは次のような多くを破るでしょう。

( echo FOO ; grep foo /etc/passwd ) | more

echoパイプに書き込んで終了します。まだEOFが発生したくありません。grepそれでもパイプに書きます。この問題は、括弧内のサブシェルの「あいまいな」場合にのみ制限されません。これは、パイプの左側でシェルスクリプトを使用するたびに発生する可能性があります。

考えると、パイプEOFメカニズムは、パイプに書き込むことができるfdとパイプでのみ読み取ることができるfdとを区別する必要があります。関連するプロセスの数によって変わりません。

関連情報