Semáfaro na execução de dois processos

17 respostas
D

ola galera blz!!!

alguem sabe alguma classe que implementa semáfaro??

que tipo , eu lanço dois processos um em seguida do outro e são dois processos demorados , mais eu preciso que o primeiro acabe totalmente pra que depois inicie o segundo

assim

processo um;
processo dois;

c não tiver semáfaro acontece de os dois serem executados sem ao menos ter terminado o primeiro ,mais o segundo depende do resultado do primeiro e sendo assim da erro…

c alguem puder me ajudar eu agradeço!!!

17 Respostas

diego2005

Não entendi muito bem, mas por exemplo, você tem o processo A e o B. O processo B não pode ser executado enquanto o A não terminar sua execução, é isso??? Ou viajei??

Se for isso você pode utilizar o método join() da classe Thread.

Se eu viajei desconsidera…heheehehehhehe

D

o diego é isso mesmo cara , o processo B só pode ser executado após o termino do A … vc tem algum exemplo de como usar esse join()???

valew

Bohzzu

Cara, a classe que implementa no java 5.0 é java.util.concurrent.Semaphore

Mas acho que o que você precisa aí é ou usar barreira ou usar ‘future’ (mas creio ser barreira mesmo). De qualquer forma, há implementações de ambos no pacote java.util.concurrent . Lá tem um bom suporte pra se trabalhar com multi-threading…

Espero ter ajudado.

[]s

D

e aew Bohzzu blz

cara então eu to atraz disso faz algum tempo ja e não to conseguindo ,eu tava usando Thread mais não tava resolvendo o meu problema , é que tipo , a minha necessidade é mais ou menos assim , eu vou executar um processo de backup e isso leva alguns minutos , então eu tenho que esperar que ele acabe pra mim poder disparar uma msg de “Backup Concluído” entende…
c eu não tiver um esquema que primeiro espera o backup terminar pra depois dispara a msg , então ela é disparada logo que eu inicio o backup
sera que vc tem alguma idéia pra me ajudar??

Bohzzu

Você precisa usar uma barreira (java.util.concurrent.CyclicBarrier)

Barreiras servem pra segurar Threads até que um numero x de threads tenham “atingido” a barreira, podendo então serem liberadas pra continuar a execução.

No seu caso vc precisa de uma barreira que deve segurar a primeira thread até a segunda chegar nela. Ou seja, vc deve criar a barreira, de “tamanho” 2, e passá-la para as duas threads. Na thread que irá mostrar a mensagem vc chama, no inicio do run o metodo await da barreira. Na outra thread vc faz isso so quando for o momento da primeira thread ser liberada.

=]

D

vc por acaso não sabe de nem um tutorial onde eu possa dar uma olhada nessa classe , o documento da sun ta muito vago

Bohzzu

Nem sei! :frowning:

Mas nem é tão complicado assim.

Primeiramente você precisa criar a barreira passando quantas Threads esta barreira deve esperar (new CyclicBarrier(2)) .

Depois você precisa passar esta barreira para a suas Threads e elas devem chamar o metodo await() quando elas precisarem esperar outras threads para continuar o trabalho ou quando elas chegarem no ponto onde as demais threads devem continuar o trabalho.

Por exemplo, você deve chamar o metodo await() no inicio da metodo run da Thread que vai exibir a mensagem. Isso indica que ela vai esperar na barreira até que duas threads chamem o metodo await(), fazendo com que a barreira libere as duas threads.

A thread que faz o backup deve fazer todo o trabalho, enquanto a outra thread espera por ela, e quando terminar deve chamar o await() pra informar a barreira que ela atingio o ponto que precisava, fazendo com que a barreira libere as duas threads pra executarem. Como a thread de backup não vai ter mais nada pra fazer (suponho), ela morrerá e a outra vai seguir executando.

:smiley:

D

eu tenho que fazer algo assim????

Runnable run = new Runnable() {
            public void run() {
                try{
                    new DBackupBancoPostgres("127.0.0.1","postgres",diretorioBackup +"\\panificadora.backup" ,"panificadora");
                }catch(Exception ex){
                    JOptionPane.showMessageDialog(null,ex);
                }
            }
        };
        proc = new Thread(run);
        proc.start();
        barreira = new CyclicBarrier(2,proc);
        
        
        Runnable run2 = new Runnable() {
            public void run() {
                try{
                    barreira.await();
                    JOptionPane.showMessageDialog(null,"Terminou");
                }catch(Exception ex){
                    JOptionPane.showMessageDialog(null,ex);
                }
            }
        };
        
        procMsg = new Thread(run2);
        procMsg.start();
        barreiraMsg = new CyclicBarrier(2,procMsg);
Bohzzu

Quase isso!

barreira = new CyclicBarrier(2); // a barreira ira esperar duas threads atingirem-a
Runnable run = new Runnable() {
            public void run() {
                try{
                    new DBackupBancoPostgres("127.0.0.1","postgres",diretorioBackup +"\\panificadora.backup" ,"panificadora");
                    barreira.await(); // ao terminar, notificar a barreira
                }catch(Exception ex){
                    JOptionPane.showMessageDialog(null,ex);
                }
            }
        };
        proc = new Thread(run);
        proc.start();
        
        
        Runnable run2 = new Runnable() {
            public void run() {
                try{
                    barreira.await(); // aqui ok! espera na barreira até duas threads a atingirem.
                    JOptionPane.showMessageDialog(null,"Terminou");
                }catch(Exception ex){
                    JOptionPane.showMessageDialog(null,ex);
                }
            }
        };
        
        procMsg = new Thread(run2);
        procMsg.start();
D

cara fiz do jeitinho que vc me falou mais não adiantou nd , ele dispara os dois processos de uma só vez , não espera o backup terminar pra mostrar a msg

Bohzzu

Pow… deve ter alguma sutileza errado nisso aí. Eu já usei barreira uma vez e não tive maiores problemas. =\

o new DBackupBancoPostgres(“127.0.0.1”,“postgres”,diretorioBackup +"\panificadora.backup" ,“panificadora”) não inicia uma thread pra fazer backup?

para estar aparecendo a mensagem antes do backup ter terminado é porque a linha barreira.await(); logo abaixo do new DBackupBancoPostgres(…) está sendo executada antes do backup terminar, o que soa no mínimo estranho.

rodrigo_corinthians

Talvez eu possa estar falando besteira mas pra esse caso isso não adiantaria??

try { new DBackupBancoPostgres("127.0.0.1","postgres",diretorioBackup +"\\panificadora.backup" ,"panificadora"); JOptionPane.showMessageDialog(null,"Terminou"); } catch(Exception ex){ JOptionPane.showMessageDialog(null,ex); }

D

olha só , esse é e meu método que faz o backup , ele é bem simples não acredito que esteje criando uma Thread

public DBackupBancoPostgres(String endIPBanco, String usuario , String caminhoDestino , String baseDados) throws IOException{
        Runtime r = null;
        r.getRuntime().exec("C:\\Arquivos de programas\\PostgreSQL\\8.1\\bin\\pg_dump.exe" +
                    " -i -h "+ endIPBanco +" -p 5432 -U "+ usuario + " -F c -b -v -f "+  
                caminhoDestino +" "+ baseDados +"").getInputStream();
    }

cara olha isso que loucura , eu fiz da seguinte maneira

barreira = new CyclicBarrier(1);
        Runnable run = new Runnable() {
            public void run() {
                try{
                    new DBackupBancoPostgres("127.0.0.1","postgres",diretorioBackup +"\\panificadora.backup" ,"panificadora");
                    //barreira.await();
                }catch(Exception ex){
                    JOptionPane.showMessageDialog(null,ex);
                }
            }
        };
        final Thread proc = new Thread(run,"Backup");
        proc.start();
        
        System.out.println(proc.getName());
        
        Runnable run2 = new Runnable() {
            public void run() {
                try{
                    barreira.await();
                }catch(Exception ex){}
                System.out.println(proc.getState());
                JOptionPane.showMessageDialog(null,"Terminou");
            }
        };
        
        procMsg = new Thread(run2,"Mensagem");
        procMsg.start();

com esse código acontece que : se eu estiver com o meu JFrame principal , o de Menu , aberto , ele não espera o backup pra dar a msg , mais c eu minimizar o meu JFrame principal , e ficar só com o JFrame do backup aberto , ele funciona certinho ..... afff q loko....
tem alguma opnião???

Bohzzu

Vamos por partes! :smiley:

Primeiramente:

Ou seja, ao usar o Runtime esta sendo criada uma nova Thread para executar o seu comando. O que você pode fazer, que inclusive excluiria a necessidade de usar barreira, é chamar o metodo waitFor() do Process que é retornado pelo metodo exec() de Runtime. Algo assim:

Process processo = r.getRuntime().exec("C:\\Arquivos de programas\\PostgreSQL\\8.1\\bin\\pg_dump.exe" +
                     " -i -h "+ endIPBanco +" -p 5432 -U "+ usuario + " -F c -b -v -f "+  
                 caminhoDestino +" "+ baseDados +"");
processo.waitFor();

Do mais, é recomendável, ao invés de usar Runtime.getRuntime().exec(), usar a classe ProcessBuilder para criar processos. Assim, seu codigo ficaria assim:

ProcessBuilder builder = new ProcessBuilder("C:\\Arquivos de programas\\PostgreSQL\\8.1\\bin\\pg_dump.exe",
                     "-i", "-h" ,endIPBanco,"-p", "5432","-U", usuario, "-F","c","-b","-v","-f", caminhoDestino, baseDados);
Process processo = builder.start();
processo.waitFor();

Quanto ao segundo caso, eu não consigo imaginar agora porque funciona com um JFrame aberto e não funciona com outro. De toda forma usar uma barreira de “tamanho” 1 é no mínimo esquisito. A priori a barreira não serviria de nada, ja que ela esperaria apenas uma thread para liberar o fluxo, desta forma qualquer thread que chamasse o metodo await() seria logo liberada e não suspendida para esperar as demais threads.

D

Bohzzu blz

olha só , me de mais uma ajuda eu para de te encher iahuiahua..
mais é sério , a dica que vc me deu funciona perfeitamente , não preciso nem usar a barreira ... só que tem um pequeno problema , quando eu executo esse código que vc me passou

ProcessBuilder builder = new ProcessBuilder("C:\\Arquivos de programas\\PostgreSQL\\8.1\\bin\\pg_dump.exe",
                "-i", "-h" ,endIPBanco,"-p", "5432","-U", usuario, "-F","c","-b","-v","-f", caminhoDestino, baseDados);
        
        Process processo = builder.start();
        
        try{
            processo.waitFor();
        }catch(Exception ex){
        
        }

ele faz o backup certinho , só que ele ainda continua como c estivesse em processo , tipo , ele não sai da Thread que ele cria , o waitFor() reconhece que ainda está em processo , mais não esta... a chamada do Processo ainda fica em uma Thread , como c não tivesse terminado .. não c vc conssegue me entender , mais c vc puder me dar mais essa ajuda eu ficarei muito grato

Bohzzu

Dei uma buscada rápida no google e acho que o que pode estar acontecendo é que o processo esta ficando ‘travado’ por conta do ‘buffer’ de saída.
Desta forma, creio que pra resolver o problema vc precisa criar Threads para ficar lendo a saída do programa, a fim de deixar o buffer livre.

Algo assim:

Process processo = builder.start();

new Thread( new Runnable() { 
         public void run() {
               Scanner sc = new Scanner(processo.getOutputStream());
               while ( sc.hasNext() ) {
                     System.out.print( sc.next() );
                }
          }
} ).start();
new Thread( new Runnable() { 
         public void run() {
               Scanner sc = new Scanner(processo.getErrortStream());
               while ( sc.hasNext() ) {
                     System.out.print( sc.next() );
                }
          }
} ).start();

processo.waitFor();
processo.getErrortStream().close();
processo.getOutputStream().close();

Acho que desta vez deve dar certo! :smiley:

D

Bohzzu blz

cara nem sei como te agradecer mew , puts, acabei de consseguir , só tive que fazer uma alteração no seu código , pq na verdade ao invés de eu pegar a saida do comando eu tive que pegar a entrada

Scanner sc = new Scanner(processo.getInputStream());

, ficou assim o código

ProcessBuilder builder = new ProcessBuilder("C:\\Arquivos de programas\\PostgreSQL\\8.1\\bin\\pg_dump.exe",
                "-i", "-h" ,endIPBanco,"-p", "5432","-U", usuario, "-F","c","-b","-v","-f", caminhoDestino, baseDados);
         
        final Process processo = builder.start();
        
        
        
        
        new Thread( new Runnable() {
            public void run() {
                Scanner sc = new Scanner(processo.getInputStream());
                while ( sc.hasNext() ) {
                    System.out.print( sc.next() );
                }
            }
        } ).start();
        new Thread( new Runnable() {
            public void run() {
                Scanner sc = new Scanner(processo.getErrorStream());
                while ( sc.hasNext() ) {
                    System.out.print( sc.next() );
                }
            }
        } ).start();
        
        
        
        try{
            processo.waitFor();
            processo.getErrorStream().close();
            processo.getOutputStream().close();
        }catch(Exception ex){
            
        }

ouw fico te devendo essa heim , valew mesmo , muita camaradagem sua ...
há eu te avaliei tambem blz .. vlw mesmo , eu estava trabalhando nisso há s semanas ja ....
abrigado

Criado 21 de outubro de 2006
Ultima resposta 23 de out. de 2006
Respostas 17
Participantes 4