IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Java Discussion :

Pb de waitFor()


Sujet :

Langage Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé Avatar de crochepatte
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    206
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mars 2005
    Messages : 206
    Par défaut Pb de waitFor()
    Bonjour,

    Voila je suis dans une impasse et je ne comprends pas vraiment d'ou vient mon erreur.

    Mon application apelle un programme c via la console (je trouve cela plus facile que d'interfacer du c dans du java avec des jni). Ce programme prends en parametre deux fichiers contenant des sequences (pouvant aller à 100000 caracteres). Je recupere le flux de sortie de la commande, et créé un nouveau fichier où stocker les données sortantes.

    Voila le bout de code

    Runtime runtime = Runtime.getRuntime();
    Process process = runtime.exec("../bin/sim4 ../files/genome.fasta ../files/sequences.fasta A=3");

    final BufferedInputStream in = new BufferedInputStream(process.getInputStream());
    final OutputStream out = new FileOutputStream("../files/tmp.txt");
    final BufferedReader br = new BufferedReader ( new InputStreamReader(in));

    Thread t = new Thread(){
    public void run()
    {
    byte [] buffer;
    String s;
    try {
    while ( ( s = br.readLine () ) != null ) {
    System.out.println(s);
    buffer = s.getBytes();
    out.write( buffer );
    out.write('\n');
    }
    out.close();
    }
    catch ( Exception e )
    {System.out.println(e.getMessage());}
    }
    };


    if ( process.waitFor() != 0 ) {
    throw new Exception ( "erreur" );}
    else {
    t.start();
    System.out.println("fin");
    }

    Le probleme est que lorsque la taille d'un des fichiers passé en parametres (par exemple sequences.fasta) est trop grande, l'application reste bloqué: elle attend.
    Si je retire le waitFor, l'application est debloqué est tourne sans erreur...le probleme c'est que bien sûr le fichier de sortie de resultats n'est pas mis à jour à temps et je dois attendre un certain temps avant de pouvoir y lire quoi que ce soit; c'est assez genant sachant que la suite de mon code est le parcours de ce fichier afin d'en extraire de l'information.

    J'avoue ne pas savoir pourquoi le logiciel ce comporte comme ca pour des fichiers de grande taille sacahnt en console ordinaire, tout marche normalement bien sur.

    Si quelqu'un peu m'expliquer quelle est mon erreur, ou une astuce pour palier a ce problème...

    Merci beaucoup

  2. #2
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Salut,


    C'est normal puisque tu n'exécutes la lecture qu'après l'appel à waitFor() et donc la fin de ton process...

    En fait il faut comprendre comment fonctionne les flux entre le process et ton application Java.

    Les trois flux (stdin, stdout, et stderr) du process sont mappé avec trois Buffered***Stream, avec une taille tampon de 8096 bytes il me semble (mais elle peut varier d'une JVM à l'autre)...

    Lorsque le process écrit dans son stdout (ou stderr), il écrit dans le tampon correspondant. Si celui-ci est plein, le Process est bloqué jusqu'à ce que le tampon soit vidé (toutes les fonctions d'écritures/lectures sont bloquantes). Il faut donc que ton programme lise le flux correspondant pour qu'il soit vidé et que le Process puissent continuer à écrire...


    Ton code rentre donc dans un cas typique d'interblocage.
    Avec de petit fichier cela marche car le tampon n'est pas remplit. Donc le process se termine correctement...

    Avec de "gros" fichiers, le tampon est remplit et le process se trouve "en attente" afin de finir d'écrire les données, et ton appli Java attend que le Process soit fini pour les lire... interblocage !!!


    Tu dois donc lire les flux AVANT de faire le waitFor() (ou en parallèle).
    De même, je t'invite à fermer les flux que tu n'utilises pas ou bien à les consommer dans des threads séparé... sans oublier les try/finally pour fermer proprement les flux


    Enfin tu te compliques un peu la vie avec ces BufferedReader de BufferInputStream qui transformes des byte en char puis en byte... Tu gagnerais surement à gérer toi même la lecture/écriture bufférisé :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
            Runtime runtime = Runtime.getRuntime();
            final Process process = runtime.exec("../bin/sim4 ../files/genome.fasta ../files/sequences.fasta A=3");
     
            // On ferme le flux stdin puisqu'on ne l'utilise pas :
            process.getOutputStream().close();
     
            // On lit le flux d'erreur dans un thread séparé :
            new Thread() {
                @Override
                public void run() {
                    try {
                        InputStream err = process.getErrorStream();
                        try {
                            dumpStream(err, System.err);
                        } finally {
                            err.close();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }.start();
     
            // On copie le flux stdout dans un fichier
            InputStream in = process.getInputStream();
            try {
                OutputStream out = new FileOutputStream("../files/tmp.txt");
                try {
                    dumpStream(in, out);
                } finally {
                    out.close();
                }
            } finally {
                in.close();
            }
            process.waitFor();
    Avec la méthode dumpStream() codé de la manière suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
        public static void dumpStream(InputStream in, OutputStream out) throws IOException {
            byte[] buf = new byte[8096];
            int len;
     
            while ( (len = in.read(buf)) > 0 ) {
                out.write(buf, 0, len);
            }
        }
    a++

  3. #3
    Membre confirmé Avatar de crochepatte
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    206
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mars 2005
    Messages : 206
    Par défaut
    Merci pour ces explications: je confond encore un peu les stdin et stdout...
    Et merci pour ton bout de code... seulement j'ai enlevé la ligne @Override, cela entraine une erreur de complilation...mais ca a l'aire de marcher sans...
    Je ne sais pas si j'ai bien réellement bien fait?

    Merci encore

  4. #4
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par crochepatte
    seulement j'ai enlevé la ligne @Override, cela entraine une erreur de complilation...mais ca a l'aire de marcher sans...
    C'est une annotation de Java 5.0. Cela n'a aucune influence sur le code. Ca indique seulement au compilateur de vérifier qu'il s'agit bien d'une redéfinition d'une méthode de la classe parent, et c'est généré automatiquement par eclipse...

    a++

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Faire un "ou" dans la fonction waitfor de telnet
    Par jean tof dans le forum Langage
    Réponses: 2
    Dernier message: 03/02/2006, 15h57
  2. TThread::WaitFor
    Par little_cypress dans le forum C++Builder
    Réponses: 5
    Dernier message: 23/02/2005, 13h29
  3. TThread et waitfor - descripteur non valide
    Par code34 dans le forum Langage
    Réponses: 2
    Dernier message: 27/10/2003, 23h44
  4. [Turbo Pascal] [LG]Instruction "WaitFor" en pascal ?
    Par bonbon dans le forum Langage
    Réponses: 13
    Dernier message: 26/03/2003, 18h37
  5. Thread probs avec WaitFor()
    Par pixelrock dans le forum C++Builder
    Réponses: 2
    Dernier message: 04/11/2002, 09h40

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo