Process.waitFor(), corrigindo o deadlock no Windows — Blog do PV

Process.waitFor(), corrigindo o deadlock no Windows

Posted by paulovittor23 at 6 Fevereiro 2008

Category: Java

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()!

4 Comentários

  1. Keps Moreira says

    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

  2. paulovittor23 says

    Boa noite Keps, tem como se fazer isso sim.
    Montei um projetinho exemplo e te enviei por e-mail.
    Espero que ajude.

  3. Andre says

    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

  4. marcelo says

    otimo post paulo, seguinte estou com este mesmo problema com o waitFor(), mas no meu caso
    estou fazendo chamada no sistema para backup com o postgres,

    process = runtime.exec( “C:/Program Files/PostgreSQL/8.4/bin/pg_dump.exe –host 192.168.1.1 –port 5432 –username postgres –format custom –blobs –verbose –file C:/Users/Marcelo/Desktop/laudoecia.backup laudoecia” );

    com esse tipo de chamada o problema persiste mesmo com a classe da MS.

    Valeu

Deixar uma resposta

Deixar uma resposta
  • (obrigatório)
  • (obrigatório) (will not be published)
  • *