Journal petit problème avec popen()

Posté par  .
Étiquettes : aucune
0
16
mar.
2004
Bonjour tout le monde,
J'aimerais pouvoir avoir en temps réel la sortie d'une commande. Mon ami google m'a donné une fonction popen() qui répond presque à mes besoins. Mais voilà, la fonction popen() est bloquante, et moi je ne le veut pas. J'aimerais que le programme suivant affiche 10 (attente d'1 seconde) 9 (attente d'1 seconde) 8 (attente d'1 seconde) 7 (attente d'1 seconde) 6 (attente d'1 seconde) 5 (attente d'1 seconde) 4 (attente d'1 seconde) 3 (attente d'1 seconde) 2 (attente d'1 seconde) 1 (attente d'1 seconde) 0 (attente d'1 seconde)

#include
#include

using namespace std;

int main (int argc, char *argv[]) {
FILE* tmp = popen("for i in 10 9 8 7 6 5 4 3 2 1; do echo $i; sleep 1; done", "r");
char c;

while(fread(&c, sizeof(char), 1, tmp)) {
cout << c;
}
fclose(tmp);

return 0;
}

Or, il attend 11 secondes et affiche l'un coup 10 9 8 7 6 5 4 3 2 1 0. Une petite idée pour faire la même chose mais en non bloquant ? (si possible quelque chose de portable au moins sous windows et *nix)

Merci.
  • # Re: petit problème avec popen()

    Posté par  (site web personnel) . Évalué à 1.

    lances la commande dans un thread : regardes du côté de fork et redirige la sortie que tu veux exploiter.
  • # Re: petit problème avec popen()

    Posté par  (site web personnel) . Évalué à 1.

    fais des lectures non-bloquantes avec fcntl(...O_NONBLOCK) ou bien utilises select
    Mais à mon avis c'est pas compatible ouinouin, il faudra que tu passes par une bibli de plus haut niveau, la glib doit proposer ça je pense
  • # Re: petit problème avec popen()

    Posté par  (site web personnel) . Évalué à 1.

    Je crois que tu as besoin de la fonction select (sur les fichiers)

    http://www.opengroup.org/onlinepubs/007904975/functions/select.html(...)

    Tu peux tuer tes process et tout et tout !
  • # Raaahhh

    Posté par  (site web personnel) . Évalué à 3.

    misère ...

    popen est non bloquant (évidemment). Mais comme tu ne flush pas ta sortie standard, tout déboule à la fin du programme.

    Et il faut utiliser pclose pour fermer le flux (pour faire un wait sur le fils). Et tu devrais tester les valeurs de retour de popen et pclose.
    • [^] # Re: Raaahhh

      Posté par  . Évalué à 3.

      Hmm...

      Le problème ne vient pas vraiment la sortie standard : elle est bien "flushée" (on dit quoi en français ? vidée ?) après chaque retour chariot inséré par echo. C'est en revanche l'entrée standard du processus fils (celui créé par popen) qui ne l'est pas.

      Pour être encore plus constructif, donnons la solution à ce petit problème : il faut utiliser la fonction setvbuf ; en l'occurence il faut placer après le popen (et avant le fread) un setvbuf(tmp, _IONBF, 0).
  • # Re: petit problème avec popen()

    Posté par  . Évalué à 5.

    c'est à cause de la bufferisation de FILE* (d'ailleurs ton C++ il en a que le nom)


    #include <stdio.h>

    int main(int argc, char *argv[])
    {
    int c;
    FILE* tmp = popen("for i in 10 9 8 7 6 5 4 3 2 1; do echo $i; sleep 1; done", "r");

    setvbuf(tmp, NULL, _IONBF, 0);

    while( (c=fgetc(tmp)) != EOF)
    {
    putchar(c);
    }

    fclose(tmp);

    return 0;
    }


    et voilà !

    man setbuf
    man setvbuf
    • [^] # Re: petit problème avec popen()

      Posté par  . Évalué à 3.

      Merci à tous pour vois réponses (malheureusement j'ai pas eu assez de [+] pour plusser tout le monde) =)

      (d'ailleurs ton C++ il en a que le nom)
      C'est parce que ce n'était qu'un exemple =)

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.