pipeによるプロセス間通信
fork()
で作成した子プロセスと親プロセスの間で情報のやり取りをするために,IPC(Inter Process Communication)の一つであるパイプを利用した.
一度理解してしまえば特に難しいものではなかったので,文章としてまとめておく.
パイプの概要
シェルを使用していると,「何かのコマンドの出力をgrepしたい」というとき等,あるコマンドの出力を別のコマンドの入力として扱いたいということが多々ある.このような場合,「パイプ」という機能を使って次のようにコマンドを実行することで実現できる.
$ cat something.txt | grep Hello
上記のコマンドを実行すると,catコマンドの出力から, Hello
を含んでいる行のみを画面に出力させることができる.
(上記の例ではパイプを使わずともgrepコマンド単体で同じことが可能であるが)
このように,パイプの入口・出口となるファイルディスクリプタを接続することができるという機能を持つ.
パイプの利用
次のような簡単なサンプルプログラムを作成した.
特に難しいことはやっておらず,ただ単に fork()
した後,親プロセスから子プロセスに文字列を送るだけのプログラム.
パイプを使うため, fork()
を呼び出す前に pipe()
を呼び出しておく.
pipe()
システムコールを呼び出すと,引数に与えた配列の0番目に「読み取り用」,1番目に「書き込み用」のファイルディスクリプタを格納してくれる.
これらに対して書き込み・読み取りをすると,それぞれ対応するファイルディスクリプタから読み取り・書き込みを行うことができる.
pipe()
を呼び出した跡は通常通り fork()
を呼び出す.
これにより,子プロセスが作成され, pipe()
によって作成されたファイルディスクリプタのペアも複製される.
その後,親プロセスと子プロセスで,次の必要ないファイルディスクリプタをそれぞれクローズしておく.
- 親プロセス→読み取り用のファイルディスクリプタ(
fds[0]
)- 親プロセスからは書き込みのみを行うため
- 子プロセス→書き込み用のファイルディスクリプタ(
fds[1]
)- 子プロセスからは読み取りのみを行うため
あとは,通常通り read()
や write()
を呼び出すだけ.
今回は, fork()
した後でも親・子ともに同じプログラムを実行していたが, execve()
等を使って子プロセスでは別のプログラムを動作させることももちろん可能.
この場合,子プロセスで標準入力からデータを読み込みたい場合は, dup2()
を使って fds[0]
を 0
(標準入力)に複製してあげると良い.
参考文献
- Michael Kerrisk,Linuxプログラミングインタフェース,2012年12月 発行,ISBN978-4-87311-585-6