2つの簡単なプログラムがあります:A
とB
。 A
最初に実行してからB
「stdout」を取得し、A
「stdin」として使用します。 GNU / Linuxオペレーティングシステムを使用していると仮定すると、最も簡単な方法は次のとおりです。
./A | ./B
このコマンドを説明する必要がある場合は、A
生産者()から入力(読み取り)を受け取り、消費者()に書き込むB
コマンドと言いたいと思います。これは正しい説明ですか?私は何を逃したことがありませんか?
答え1
あなたの質問で目立つ唯一のことは間違ったあなたは正しいです。
Aが最初に実行され、BがAの標準出力を取得します。
実際、両方のプログラムはほぼ同時に始まりました。読み取ろうとしたときに入力がない場合は、B
読み取る入力があるまでブロックされます。同様に、誰も出力を読み取らないと、A
出力が読み取られるまで書き込みがブロックされます(一部はパイプによってバッファリングされます)。
パイプラインに参加するプロセスを同期する唯一のことは、I / O、つまりパイプライン全体で読み書きすることです。書き込みまたは読み取りが行われない場合、両方のプロセスは完全に独立して実行されます。あるプロセスが別のプロセスの読み取りまたは書き込みを無視すると、無視されたプロセスはブロックされ、最終的に信号SIGPIPE
(書き込みの場合)によって終了するか、別のプロセスが条件(読み取りの場合)になります。
これを慣用的に表現することは、A | B
2つのプログラムを含むパイプラインであるということです。標準出力の最初のプログラムで生成された出力は、標準入力の2番目のプログラムで読み取ることができます(「[の出力]はA
[の入力]にパイプされますB
」)。シェルはこれを達成するために必要なパイプ操作を実行します。
「消費者」、「生産者」という言葉を使いたいなら、それも大丈夫だと思います。
これがCで書かれたプログラムであるという事実は不適切です。これがLinux、macOS、OpenBSD、またはAIXであるという事実は不適切です。
答え2
文書で一般的に使用される用語は、1つ以上のコマンドで構成される「パイプライン」です。POSIX定義の表示fork()+exec()
したがって、技術的には2つのコマンド、2つのシェルサブプロセス(「外部コマンドの使用」または「サブシェル」)です。
については生産者 - 消費者部分的に、パイプラインは次の理由でこのパターンで説明できます。
- 生産者と消費者は、少なくともLinuxとMacOS Xでは固定サイズのバッファを共有します。パイプバッファの固定サイズ
/proc/<pid>/fd
生産者と消費者は疎結合しており、パイプラインのコマンドはディレクトリを積極的に確認しない限り、互いの存在を認識しません。- プロデューサ書き込みとコンシューマ読み取りは、実行される単一のコマンドであるかのように
stdout
記録されます。stdin
お互いがなくても存在できます。
ここで見られる違いは、他の言語の生産者 - 消費者とは異なり、シェルコマンドはバッファリングを使用し、バッファがいっぱいになるとstdoutに書き込みますが、生産者 - 消費者がその規則に従う必要があるという言及はありません。キューがいっぱいになったり削除されたときのデータ(パイプが実行しない他の操作)