web-dev-qa-db-ja.com

SIGPIPEはどのような状況で正確に発生しますか?

たとえば、fifoという名前のパイプがあり、2つの異なるシェルからパイプを読み書きしているとします。次の2つの例を検討してください。

_Shell 1$ echo foo > fifo
<hangs>
Shell 2$ cat fifo
foo
Shell 1$ echo bar > fifo
<hangs>
_

_Shell 1$ cat > fifo
<typing> foo
<hangs>
Shell 2$ cat fifo
foo
^C
Shell 1$
<typing> bar
<exits>
_

これらの例で何が起こるかについて頭を抱えることはできません。特に、最初の例でパイプに「バー」を書き込もうとするとブロッキング呼び出しが発生しますが、2番目の例ではSIGPIPEがトリガーされます。

最初のケースでは、2つの別々のプロセスがパイプに書き込むため、2回開かれますが、2番目のケースでは、単一のプロセスによって1回だけ開かれ、2回書き込まれ、プロセスはパイプから読み取ります。その間に殺された。私が理解していないのは、それがwriteの動作にどのように影響するかです。

pipe(7)のマニュアルページには、次のように記載されています。

パイプの読み取り側を参照するすべてのファイル記述子が閉じられている場合、write(2)により、呼び出しプロセスに対してSIGPIPEシグナルが生成されます。

この状態は私にははっきり聞こえません。 closedファイル記述子はファイル記述子でなくなりますよね? 「パイプの読み取り端が閉じています」と「パイプの読み取り端がどのように違うのですか?開いていません "?

私の質問が十分に明確であることを望みます。ちなみに、openclosereadおよびwrite操作に関連するUnixパイプの機能を詳しく理解するためのポインタを提案できたら、よろしくお願いします。

5
Naïm Favier

あなたの例ではfifoではなくpipeを使用しているため、 fifo(7) が適用されます。 pipe(7) は次のことも伝えます。

FIFO(先入れ先出しの略)は、ファイルシステム内に名前があり(mkfifo(3)を使用して作成)、open(2)を使用して開かれます。どのプロセスでもFIFOを開くことができます。ファイルのアクセス許可で許可されていることを前提としています。読み取り側はO_RDONLYフラグを使用して開かれ、書き込み側はO_WRONLYフラグを使用して開かれます。詳細については、fifo(7)を参照してください。注:FIFOのパス名はファイルシステムにありますが、FIFOのI/Oは、基礎となるデバイス(存在する場合)での操作を含みません。

パイプとFIFOのI/O
パイプとFIFOの唯一の違いは、パイプが作成されて開かれる方法です。これらのタスクが完了すると、パイプとFIFOのI/Oはまったく同じセマンティクスになります。

だから今 fifo(7) から:

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

したがって、両端(ここでは、少なくともリーダーとライターがあることを意味します)が開かれる前に、fifo(7)に従ってブロックを書き込みます。両端が開かれ、読み取り端が閉じられた後、書き込みはpipe(7)に従ってSIGPIPEを生成します。

(fifoではなく)パイプの使用例については、 pipe(2) の例のセクションを参照してください:pipe()は実際にパイプペアを作成したため、pipe()を含みます(open()なし)。 open)、close()、read()、write()、fork()(パイプを使用する場合、ほとんど常にfork()があります)。

Fifoへの書き込み時にSIGPIPEを終了させたくない場合に、自分のCコードからSIGPIPEを処理する最も簡単な方法は、signal(SIGPIPE, SIG_IGN);を呼び出し、errno EPIPEをチェックして処理することです。代わりに各write()の後。

8
A.B

パイプへの書き込み、またはFIFOは、エラー状態として扱われます。これはSIGPIPEシグナルを生成し、シグナルが処理またはブロックされるとエラーコードEPIPEで失敗します。

1
Mumtaz Ahmad