これが私のシナリオです:
- プロセス A は子プロセス B を生成し、スレッドをスピンして B の出力をドレインします。
- プロセス B はデーモン プロセス C を生成し、その出力も排出します。
- プロセス B が終了しても、デーモン プロセスは存続します。
- プロセス A は、プロセス B が process.waitFor() を介して終了したことを検出します。ただし、プロセス B の入力ストリームの読み取りでスタックしています。これは、B がデーモンを開始したためです。入力ストリームは、プロセス C が終了したときにのみ EOF を受け取ります。
これは Windows でのみ発生します。ProcessBuilder を使用しています。私が思いついた解決策は次のとおりです。私が本当に気に入っている解決策はありませんので、フィードバックをお寄せください。
- jna を使用してデーモン プロセス C を生成できます。このようにして、「十分に切り離された」プロセスを作成でき、プロセス A は B からのストリームの排出に固執しません。それは機能しますが、私はその解決策にあまり熱心ではありません。それはいくつかのネイティブ コードを意味します (そして、私は入力を消費することに熱心なので、その多くを意味します)。JNAを介してそれを行う方法のインスピレーションは、http: //yajsw.sourceforge.netにあります(ただし、単なるプロセス開始よりもはるかに多くのものが含まれています)。
- jre7 で実行します。Jdk7 は ProcessBuilder にいくつかの新しい機能をもたらします。たとえば、私の問題も解決する inheritIO() などです。どうやら、inheritIO() がオンになっていると、デーモン プロセス C のすべてのストリームを単純に閉じることができ (これはデーモンなのでとにかくそうします)、問題は解決します。ただし、jre5+で実行する必要があります
- デーモン プロセス C を生成する前に、プロセス B の System.out と System.err を閉じます。これで問題は解決しますが、これらのストリームに有用なものを書き込むため、プロセス B でこれらのストリームを動作させる必要があります。ダメ。B と C の間にある種のブートストラップ プロセスを配置することで、この特性を利用できることを望んでいましたが、問題は解決しませんでした。
- Linux ではその問題は発生しないので、Linux でのみ実行できますか? いいえ、できません。
- プロセスAがプロセスBの出力をブロックしない方法で排出するようにしました。これはある程度機能しますが、便利ではありません。たとえば、inputStream.read() は中断できません。inputStream.available() を使用できますが、EOF と zero-bytes-available を区別しません。したがって、プロセス A が B の出力 EOF に関心がない場合にのみ、解決策は適切です。また、このソリューションはより CPU を集中的に使用するようであり、一般的には... ぎこちなく、防弾とは言えません。
- プロセス C を --dry-run モードで実行します。このモードでは、開始できるかどうかを確認するだけです。起動を試み、ウェルカム メッセージを送信して終了します。長時間実行されなくなったため、読み取りをブロックしません。プロセス B は、C を開始できるという十分な信頼を得ることができ、比較的単純な JNA コードを使用して、その出力を消費せずに切り離されたプロセスを生成できます (出力を消費すると、JNA 関連のコードが煩雑で重くなります)。唯一の問題は、C の出力をコンシューマ処理しなくなったことですが、プロセス B がコンシューマできる既知のファイルに C を書き込むことで解決できます。このソリューションは、大きくて醜い回避策のようなものですが、私たちにとっては実行可能です. とにかく、私たちは解決策 1) を現在試しています。
ヒントをいただければ幸いです。