0

このコード (以下) をいくつかの異なる Linux ボックス (4+) でテストしたところ、問題なく動作しました。しかし、ある Linux ボックスで、エラー inputStream(errorStream) のために readline() がハングするという問題に遭遇しました。このストリームは空でなければならないので、ボックスがエラーの errorStream に行末記号を書き込んでいないのではないかと疑っていました。readline() の代わりに read() を使用するようにコードを変更しましたが、read() もハングしました。

最初に入力inputStreamを取得しようとしましたが、それは機能し、エラーinputstreamのreadline()/ read()でハングすることはありませんでした。可能性のあるエラーを最初に取得する必要があったため、これを行うことができませんでした。デッドロックのように見えますが、各入力ストリームを独自のスレッドから読み取ることでこれを解決できました。この問題が 1 つのボックスでしか見られなかったのはなぜですか? これを引き起こした可能性のある、このボックスに固有のカーネル設定またはその他の設定はありますか?

   ProcessBuilder  processBuilder = new ProcessBuilder()
   try 
   {
       Process processA = null;
       synchronized (processBuilder)
       {
           processBuilder.command("/bin/sh","-c"," . /Home/SomeScript.ksh");
           processA = processBuilder.start();
       }

       inputStream = processA.getInputStream();
       reader = new BufferedReader(new InputStreamReader(inputStream));

       errorStream = processA.getErrorStream();
       errorReader = new BufferedReader(new InputStreamReader(errorStream));

       String driverError;

       while ((driverError = errorReader.readLine()) != null)
       {
           //some code
       }
4

2 に答える 2

1

スクリプトで OS 固有のコマンドを実行していますが、どれもエラー出力を保持している可能性があります。エラーを破棄することでこれを回避できますが、それは良い考えではありません。

OS のバージョンが同じであること、およびスクリプトで実行するコマンドに大きな違いがあるかどうかを確認します。これで問題が解決しない場合は、スクリプトが機能し始めるまで、スクリプトからコマンドを取り出します。空のスクリプトはこれを行わないと思います。

于 2013-08-02T05:35:21.147 に答える
1

この問題が 1 つのボックスでしか見られなかったのはなぜですか?

おそらく、実行中のスクリプト内の何かと、その環境との相互作用 (ファイル、環境変数など) が原因である可能性があります。

これを引き起こした可能性のある、このボックスに固有のカーネル設定またはその他の設定はありますか?

可能性はありますが、カーネル設定である可能性は低いです。それは「別の何か」かもしれません。実際、少なくとも部分的に責任があるのは、Java アプリケーションの外部にある「何か」に違いありません。


一時的に(少なくとも)次のことを行うことをお勧めします。

   ProcessBuilder  processBuilder = new ProcessBuilder();
   processBuilder.command("/bin/sh","-c"," . /Home/SomeScript.ksh");
   processBuilder.redirectErrorStream(true);

   processA = processBuilder.start();

   inputStream = processA.getInputStream();
   reader = new BufferedReader(new InputStreamReader(inputStream));
   String line;

   while ((line = reader.readLine()) != null) {
       System.out.println(line);
   }
   System.out.println("Return code is " + processA.exitValue());

そうすれば、すべての出力が何であるかを確認できます。

外部プロセスが最終行の最後に改行を入れなくても問題はありません。Java プロセスは入力ストリームで EOF を確認し、含まれてBufferedReaderいる文字を返します...そしてnull次の呼び出しで戻ります。


もう 1 つの可能性は、外部プロセスが標準入力から読み取ろうとしているためにブロックされていることです。


アップデート

redirectErrorStream も問題を解決しましたが、別のエラー ストリームが必要です。

問題が(確実に)解決された場合、それは(おそらく)外部プロセスstdoutstderrストリームを並行して読み取る必要があることを意味します。簡単な方法は、2 つのストリームを別々に読み取り、バッファリングする 2 つのスレッドを作成することです。例: Runtime.exec の呼び出し時に stdout をキャプチャする

stdout(あなたの問題は、パイプのバッファリング容量が有限であるという事実によるものです。外部の問題は、とへの書き込みを交互に行う可能性が最も高いstderrです。パイプが「いっぱい」のときにパイプの1つに書き込もうとすると、ブロックされます. しかし、アプリケーションがブロックされたパイプを読み取る前に他のすべてのパイプ (EOF まで)を読み取っている場合、すべてがデッドロックになります. 外部プロセスが PIPE_W 状態でスタックしているという事実は、この説明のより多くの証拠です.

異なるシステムで異なる動作が見られる理由の 1 つは、パイプ内のバッファリングの量がシステムに依存していることです。しかし、外部プロセスが行っていることの違いが原因である可能性もあります。例えば、その入力。)

于 2013-08-02T06:00:11.413 に答える