読者です 読者をやめる 読者になる 読者になる

CreatePipe

Windowsで名前なしパイプを作成するには、CreatePipeを使う・・・。

CreatePipe 関数

WindowsAPIにはforkが無いし、パイプの扱い方もUNIXとは違うので、パイプによるプロセス間通信の実装は結構難しい・・・。

C言語CreatePipeメモ(Hishidama's Windows C "CreatePipe" Memo)

上記を参考に、UNIXシステムコールのpipeでやったようなプログラムをWindowsAPIでもやってみる・・・。

f:id:BG1:20170316230844p:plain

コンソールの、

f:id:BG1:20170316230937p:plain

空プロジェクトで、CreatePipe.cppを追加したら、

親が書き込んで子が読むパイプ配列hPipe1、子が書き込んで親が読むパイプ配列hPipe2、子が親からの読み込みに使うパイプhChildRead、子が親への書き込みに使うパイプhChildWrite、の6つのハンドルを用意・・・。

CreatePipeでhPipe1[0]に読み込みパイプ、hPipe1[1]に書き込みパイプが格納される・・・。
しかし、実際にはhPipe1[0]は親側では使わない・・・。
そして、第3引数がNULLだと、子プロセスに渡して使わせることができない・・・。
しかし、ここではあえてNULLにしている・・・。

いったんどちらのパイプも継承不可能にしつつ、DuplicateHandleでhPipe1[0]を複製してhChildReadに格納・・・。
ここで第6引数がTRUEだと、こちらのhChildReadは子プロセスに渡して読み込みに使うことができる・・・。

使わないhPipe1[0]はCloseHandleで閉じる・・・。

ここまでで、親プロセスの書き込みはhPipe1[1]、子プロセスの読み込みはhChildReadとなる・・・。

hPipe2はさっきとは逆で、実質hPipe2[1]を使わない・・・。

hPipe2[1]を複製してhChildWriteとする・・・。

hPipe2[0]は親プロセスの読み込み、子プロセスからの書き込みはhChildWriteとなる・・・。

使わないhPipe2[1]を閉じる・・・。

CreateProcessで"ChildProcess.exe"を起動する・・・。
si.hStdInputに子が読み込む用のハンドルhChildReadを渡して、子プロセスの標準入力が親プロセスからの読み込みになるようにしている・・・。
si.hStdOutputに子が書き込む用のハンドルhChildWriteを渡して、子プロセスの標準出力が親プロセスへの書き込みになるようにしている・・・。

3秒待って、

"I am Parent!"を子プロセスに向けて書き込む・・・。

さらにその9秒後に子プロセスからのメッセージを読み込んで出力・・・。
今回、子プロセスの標準入力をhChildRead、標準出力をhChildWriteに換えているので、標準エラー出力に出力する_tperrorを使って、文字列出力をする・・・。

ChildProcess.cppは、

6秒後にfgetsで親プロセスから子プロセスに送られてきたメッセージを読み込んで"Child: "を付けて出力・・・。
そのあと、3秒待って、子プロセスから親プロセスにfputsで"I am Child!"を送る・・・。

2つのプログラムのうち、CreatePipeを実行すると、

Parent: I am Parent!: No error
Child: I am Parent!: No error
Child: I am Child!: No error
Parent: I am Child!: No error

3秒ごとにParent, Child, Child, Parentとなっていて、Childが"I am Parent!"を読み込んでたり、ParentでI am Child!を読み込んでたりするのがわかる・・・。

Sample/winapi/CreatePipe/CreatePipe/src/CreatePipe at master · bg1bgst333/Sample · GitHub