web-dev-qa-db-ja.com

Process.waitFor()、スレッド、およびInputStreams

疑似コードで、私がやっていることはここにあります:

_Process proc = runtime.exec(command);
processOutputStreamInThread(proc.getInputStream());
processOutputStreamInThread(proc.getErrorStream());
proc.waitFor()
_

ただし、processOutputStreamInThreadに出力が表示されない場合と表示される場合があります。おおまかに言って、このメソッドはコマンドの出力のBufferedInputStreamを作成し、ロガーに送信します。

私が見ていることに基づいて、私はcommandgetInputStream()およびgetErrorStream()によって供給されるストリームにダンプされるすべての出力を必要としないため、空にするストリーム。

私の裁判の結果は次の質問です:

(1)Java.lang.ProcesswaitFor()は、実行されたプログラムの出力が戻る前に読んだ?

ドキュメントには、次のようにのみ記載されています。

必要に応じて、このProcessオブジェクトで表されるプロセスが終了するまで、現在のスレッドを待機させます。このメソッドは、サブプロセスがすでに終了している場合はすぐに戻ります。サブプロセスがまだ終了していない場合、呼び出しスレッドはサブプロセスが終了するまでブロックされます。

(2)どのような条件下で、getInputStreamおよびgetErrorStreamによって提供されるストリームを閉じる必要があるか、または彼らは自動的に閉じましたか?

ドキュメントには、次のようにのみ記載されています。

サブプロセスのエラーストリームを取得します。ストリームは、このProcessオブジェクトによって表されるプロセスのエラー出力ストリームからパイプされたデータを取得します。

実装上の注意:入力ストリームをバッファリングすることをお勧めします。

1つ ユーザーレポート 彼は自分でストリームを閉じなければならなかったが、少なくとも一部の時間で例外が発生し、ストリームを閉じようとしたときに、すでに閉じられていることが示されている。

編集:getOutputStreamgetInputStreamに変更しました。

解決策:問題は、出力ストリームの処理に使用されるスレッドが、非常に短期間のプロセスが実行されるまで実行されないということでした。完了しました。結果として、入力ストリームはデータを提供しなくなりました。 waitForは、実行されたプログラムの出力を待機していませんでした。むしろ、プログラムは実行され、出力が収集される前に終了しました。

標準エラーと標準出力でどのくらいの出力を取得するのかわからないため、スレッドを使用しました。どちらか一方のみがデータを利用できる場合、どちらか一方をブロックせずに両方を同時に処理できるようにしたいと考えました。しかし、私のスレッドは実行されたプログラムの出力を一貫して読み取ることができないため、これは解決策ではありません。

私の最終的なコードは次のようになりました:

_ProcessBuilder pb = new ProcessBuilder(cmdargs);
pb.redirectErrorStream(true);
Process proc = pb.start();
processOutputStream(proc.getInputStream());
proc.waitFor()
_
32
Kaleb Pederson

外部プロセスがstdinで何かを予期している場合は、getOutputStreamを閉じる必要があります。そうでなければ、あなたは永遠にwaitForするでしょう。

以下は Runtime.exec()が記事を作成しない場合 のJavaWorldで、execメソッドのさまざまな落とし穴とその回避方法を説明しています。

私の経験から、子プロセスのSTDOUTとSTDERRを(EOF)まで)消費し、waitForでブロックすることをお勧めします。この時点で、待つ必要がないことを願います。

カレブの質問への答え。通常の状態ではストリームを閉じないでください。ただし、あなたはwaitingForであり、なんらかの理由でタイムアウトがないため、出力でエラー条件が発生した場合にこれらのストリームを閉じて、子の出力をさらに処理したくない。ただし、子プログラムがSTDOUTまたはSTDERRパイプがもう一方の端で閉じられたときに終了する(クラッシュする)かどうかは、完全にその子の実装次第です。ただし、ほとんどのシェルプログラムはこのような状況で終了します。

waitForに意味のあるタイムアウトがあり、Processが監視を中止することにしたときに、リソースをクリーンアップする方法が文書化されていることを本当に望みます。

29

これは少し直感に反すると思いますが、次のようになります。

getOutputStreamサブプロセスの出力ストリームを取得します。ストリームへの出力は、このProcessオブジェクトで表されるプロセスの標準入力ストリームにパイプされます。実装上の注意:出力ストリームをバッファリングすることをお勧めします。戻り値:サブプロセスの通常の入力に接続された出力ストリーム。

これをメインプロセスからのこの出力ストリームとして読み取り、サブプロセスの標準入力にアタッチしているため、getOutputStream()。write()に書き込むときは、実際にはstdinに書き込んでいます。

おそらく.getInputStream()を使用しますか?

戻り値:サブプロセスの通常の出力に接続された入力ストリーム。

Process.Waitfor()に関しては、APIドキュメントは次のように言っています:

現在のスレッドは、必要に応じて、このProcessオブジェクトで表されるプロセスが終了するまで待機します。このメソッドは、サブプロセスがすでに終了している場合はすぐに戻ります。サブプロセスがまだ終了していない場合、呼び出しスレッドはサブプロセスが終了するまでブロックされます。

これが呼び出されたスレッドは、プロセスの実行が終了するまでブロックされます-他のスレッドによっては、この段階で出力を処理している場合もあれば、スレッドが戻る前に終了した場合もあります。

2
user257111