私は、JavaのProcessBuilderを使用して、「長期」で実行する必要のあるアプリケーションをLinuxで起動しようとしています。このプログラムの実行方法は、コマンドを起動し(この場合は、メディア再生アプリケーションを起動しています)、実行を許可し、クラッシュしていないことを確認することです。たとえば、PIDがまだアクティブかどうかを確認し、プロセスが停止している場合はプロセスを再起動します。
私が今得ている問題は、PIDがシステム内に残っているが、アプリケーションのGUIがハングすることです。 ProcessBuilder(cmd).start()を別のスレッドにシフトしてみましたが、期待どおり、何も解決されていないようです。
基本的に、結果として、ユーザーにとってプログラムはクラッシュしたように見えますが、ProcessBuilder.start()プロセスを駆動するJavaプロセスを強制終了すると、実際には、作成されたプロセスが通常の動作を再開できます。 。これは、Javaアプリケーション内の何かが、生成されたプロセスを妨害していることを意味しますが、現時点では、何が起きているのかまったくわかりません。何も解決しないようです)
誰かが何かの意見や考えを持っている場合は、私に知らせてください。私の問題では、この問題を解決する方法を考えることはできません。
編集:私はプロセスから作成されたI/Oストリームについて心配していないため、それに対処するための手順を実行していません。これにより、プロセス自体がハングする可能性はありますか?
プロセスがstderrまたはstdoutに書き込んでいて、それを読み取っていない場合は、単に "ハング"し、stdout/errへの書き込み時にブロックされます。シェルを使用してstdout/errを/ dev/nullにリダイレクトするか、またはstdout/errをredirectErrorStream(true)とマージして、プロセスのstdoutから読み取る別のスレッドを生成します
あなたはtheトリックが欲しいですか?
ProcessBuilder.start()からプロセスを開始しないでください。 Javaからのストリームのリダイレクト/消費を混乱させないでください(特に、それについてs ** tを指定しない場合;))
ProcessBuilder.start()を使用して、すべての入出力ストリームを取得する小さなシェルスクリプトを開始します。
そんな感じ:
#!/bin/bash
Nohup $1 >/dev/null 2>error.log &
つまり、stdoutを気にせずにstderrをログに記録したい場合(そうですか?)(error.log here)にログを記録します。
Stderrも気にしない場合は、stdoutにリダイレクトするだけです。
#!/bin/bash
Nohup $1 >/dev/null 2>1 &
そして、その小さなスクリプトをJavaから呼び出し、実行するプロセスの名前を引数として渡します。
Stdoutとstderrの両方を/ dev/nullにリダイレクトするLinuxで実行中のプロセスがanythingを生成する場合は、準拠していない、壊れたLinuxインストールがあります;)
つまり、上記のJust Works [TM]を削除して問題のある"このストリームを消費する必要があり、その順序でbla bla bla Java固有の意味がない"を削除します。
プロセスを実行するスレッドは、出力を処理しない場合、ブロックすることがあります。これは、プロセスの出力を読み取る新しいスレッドを生成することで実行できます。
final ProcessBuilder builder = new ProcessBuilder("script")
.redirectErrorStream(true)
.directory(workDirectory);
final Process process = builder.start();
final StringWriter writer = new StringWriter();
new Thread(new Runnable() {
public void run() {
IOUtils.copy(process.getInputStream(), writer);
}
}).start();
final int exitValue = process.waitFor();
final String processOutput = writer.toString();
私が同様の問題を抱えた後、これに偶然遭遇しました。 nosに同意すると、出力を処理する必要があります。私はこのようなものを持っていました:
ProcessBuilder myProc2 = new ProcessBuilder(command);
final Process process = myProc2.start();
そしてそれは素晴らしかった。生成されたプロセスは出力someも出力しましたが、多くは出力しませんでした。私がもっとたくさん出力し始めたとき、私のプロセスはもう起動されていなかったように見えました。私はこれに更新しました:
ProcessBuilder myProc2 = new ProcessBuilder(command);
myProc2.redirectErrorStream(true);
final Process process = myProc2.start();
InputStream myIS = process.getInputStream();
String tempOut = convertStreamToStr(myIS);
そして、それは再び働き始めました。 (convertStreamToStr()コードについては、このリンクを参照してください: http://singztechmusings.wordpress.com/2011/06/21/getting-started-with-javas-processbuilder-a-sample-utility-class-to -interact-with-linux-from-Java-program / )
JDK7には、サブプロセスI/Oリダイレクトの組み込みサポートがあります。
http://download.Oracle.com/javase/7/docs/api/Java/lang/ProcessBuilder.html
それまでの間、本当にstdout/stderrを破棄したい場合、(Linuxでは)次のようなコマンドでProcessBuilderを呼び出すのが最善のようです。
["/bin/bash", "-c", "exec YOUR_COMMAND_HERE >/dev/null 2>&1"]
編集:私はプロセスから作成されたI/Oストリームについて心配していないため、それに対処するための手順を実行していません。これにより、プロセス自体がハングする可能性はありますか?
プロセスによって作成された出力ストリームを読み取らない場合、アプリケーションのバッファーがいっぱいになると、アプリケーションがブロックする可能性があります。これがLinuxで発生することは一度もありませんが(発生しないとは言っていません)、Windowsでこの問題が発生することは確認済みです。これはおそらく関連していると思います。
別の解決策は、Redirect.PIPE
でプロセスを開始し、次のようにInputStream
を閉じることです。
ProcessBuilder builder = new ProcessBuilder(cmd);
builder.redirectOutput(Redirect.PIPE);
builder.redirectErrorStream(true); // redirect the SysErr to SysOut
Process proc = builder.start();
proc.getInputStream().close(); // this will close the pipe and the output will "flow"
procp.waitFor();
私はこれをWindowsとLinuxでテストし、動作しました!
問題はLinux自体からのバッファリングパイプにあると思います。
実行可能ファイルでstdbuf
を使用してみてください
new ProcessBuilder().command("/usr/bin/stdbuf","-o0","*executable*","*arguments*");**
-o0
は、出力をバッファリングしないことを示します。同じことが-i0
および-e0
入力とエラーパイプのバッファを解除する場合。
Stdoutとstderrをキャプチャしてプロセスを監視する必要がある場合は、 Apache Commons Exec を使用すると非常に役立ちます。