2 つのプロセスの間のパイプは、親プロセスで作成されているファイルのペアです。パイプは、親プロセスがフォークしたときの結果のプロセスを接続します。パイプは、ファイル名空間には存在しないため、「匿名」と呼びます。パイプは通常 2 つのプロセスだけを接続しますが、任意の数の子プロセスを相互に接続したり、あるいは 1 本のパイプでその子プロセスに関連する親プロセスと接続したりすることもできます。
パイプは、親プロセスで pipe(2) 呼び出しを使用し作成されます。pipe(2) は引数の配列に 2 つのファイル記述子を返します。フォーク後、両方のプロセスは p[0] から読み取り、p[1] に書き込みます。実際には、これらのプロセスが読み取りまたは書き込みを行うのは循環バッファーに対してであり、この循環バッファーを管理することによって、プロセスの代わりにパイプとの読み取りまたは書き込みを行うことができます。
fork(2) を使用すると各プロセスの開いているファイルテーブルが複写されるので、各プロセスは 2 つのリーダー (読み取り用パイプ) と 2 つのライター (書き込み用パイプ) を持つことになります。パイプを適切に機能させるには、余分なリーダーとライターを閉じる必要があります。たとえば、同じプロセスが片方のリーダーを書き込み用に開いたまま、もう一方のリーダーから読み取ろうとすると、EOF (ファイルの終わり) は返されません。次のコードは、パイプの作成、フォーク、および重複したパイプの終わりのクリアを示しています。
#include <stdio.h> #include <unistd.h> ... int p[2]; ... if (pipe(p) == -1) exit(1); switch( fork() ) { case 0: /* in child */ close( p[0] ); dup2( p[1], 1); close P[1] ); exec( ... ); exit(1); default: /* in parent */ close( p[1] ); dup2( P[0], 0 ); close( p[0] ); break; } ...
ある条件下で、パイプからの読み取りパイプへの書き込みを行うと、次の表のようになります。
表 7–1 パイプでの読み取りと書き込みの結果
実行 |
条件 |
結果 |
---|---|---|
読み取り |
空のパイプ、ライター接続 |
読み取りはブロックされる |
書き込み |
フルのパイプ、リーダー接続 |
書き込みはブロックされる |
読み取り |
空のパイプ、接続ライターなし |
EOF が戻される |
書き込み |
リーダーなし |
SIGPIPE |
fcntl(2) を記述子に呼び出して FNDELAY を設定すると、ブロックを阻止でき、この状態で入出力関数の呼び出しを行うと、errno に EWOULDBLOCK が設定され、エラー -1 が返されます。