Process.waitFor(), corrigindo o deadlock no Windows
Process.waitFor(), corrigindo o deadlock no Windows
Há um tempo atrás eu estava desenvolvendo uma mini biblioteca para trabalhar a execução de comandos no SO de uma forma mais amigável, uma espécie de DSL. Criada a biblioteca realizei alguns testes em ambiente Linux. Tudo funcionamento dentro do planejado, hora de utilizá-la…
Bom, na primeira real utilização da biblioteca, em ambiente Win32 executei um “ipconfig /all”, e para minha surpresa, após todos os testes que havia realizado o comando simplesmente não respondeu.
Voltei ao Linux, mudei o comando para “ifconfig” e o comando executou sem problemas…
Comecei a debugar a biblioteca afim de descobrir o que estava causando o congelamento na execução do comando no SO… Após alguns minutos, cheguei finalmente ao método “waitFor()” da classe “Process”… pela definição esse método faz com que a thread corrente espere, caso necessário, até o processo representado pelo objeto Process terminar.
A questão é que o método “Runtime.exec()” (que devolve a instância do processo criado) cria um pipe para a saída padrão e quando um processo filho escreve uma quantidade grande de dados neste pipe, de modo a deixar o buffer cheio, o pipe é bloqueado pelo Windows até que o processo pai leia esse buffer. Logo, caso o processo pai nunca leia a saída padrão do processo filho teremos um deadlock.
Segundo a documentação da Microsoft para prevenir este bloqueio devemos garantir que o processo pai sempre leia a saída padrão do processo filho… Mas será que o Windows não deveria fazer isso por padrão ao invés de transferir essa responsabilidade aos utilizadores do SO? Enfim…
E como fazer para utilizar o waitFor() no Windows?
A própria Microsoft desenvolveu uma classe que deve ser utilizada antes da chamada ao waitFor…
Um exemplo de utilização dessa classe:
package org.paulovittor23.fixing.waitfor;
import java.io.IOException;
/**
*
* @author Paulo Vitor Rendeiro
* @mail paulovittor23@gmail.com
* @site http://paulovittor23.org
*
* FixingWaitForOnWindows.java
*
*/
public class FixingWaitForOnWindows {
public static void main(String[] args) {
Runtime runtime = Runtime.getRuntime();
Process process = null;
try {
process = runtime.exec( "ipconfig /all" );
/* instância a classe da MS
* passando como parâmetro a stream de
* entrada do sub-processo */
new PrintStream( process.getInputStream() ).start();
/* agora podemos fazer a chamada ao waitFor
* sem que o mesmo cause deadlock */
process.waitFor();
}catch(IOException e) {
e.printStackTrace();
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
class PrintStream extends Thread {
java.io.InputStream __is = null;
public PrintStream(java.io.InputStream is) {
__is = is;
}
public void run() {
try {
while (this != null) {
int _ch = __is.read();
if (_ch != -1)
System.out.print((char) _ch);
else
break;
}
}catch(Exception e) {
e.printStackTrace();
}
}
}
Já realizei testes utilizando essa classe no Linux e o funcionamento permanece normal.
Sempre que for executar algum comando no Windows é bom atentar para utilização do método waitFor()!
Oi estava mesmo com problema com o waitFor() no windows, boa dica.
Gostaria de saber se tem como armazenar essa saida em uma String por exemplo?
Grato
Boa noite Keps, tem como se fazer isso sim.
Montei um projetinho exemplo e te enviei por e-mail.
Espero que ajude.
Tentei executar este código em uma jsp, mas o processo não abre,
Tenho um contexto no tomcat que fica na pasta
c:\Arquivos de Programas\aplicacao
estou tentando executar um arquivo.bat para fazer backup do postgres
mas o mesmo aparece nos processos e nunca conclui
Agradeço anteciapadamente