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 Perl Discussion :

Problème fermeture de pipe


Sujet :

Langage Perl

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    45
    Détails du profil
    Informations personnelles :
    Localisation : France, Morbihan (Bretagne)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 45
    Points : 29
    Points
    29
    Par défaut Problème fermeture de pipe
    Bonjour,

    j'ai un problème pour fermer un pipe ouvert via open(FH, "|....."). Au cas où cela a une importance, je précise que je travaille sur MacOS Darwin Mavericks 10.9.5.

    Voici le traitement que je fais :
    1) j'ouvre un pipe via open(PIPE, "|......") qui lance un programme demandant en boucle des réponses et ne s'arrete pas tant qu'il n'a pas reçu une réponse d'arret bien précise (par exemple la lettre f)
    2) je donne des réponses via print PIPE "....."
    3) je ferme le pipe via close(PIPE)
    => au moment de la fermeture, j'obtiens un affichage en boucle infinie si la réponse d'arret n'a pas été donnée

    Auriez-vous une idée pour gérer ce problème qui peut s'avérer problématique si l'affichage est redirigé vers un fichier dont la taille va gonfler gonfler jusqu'à remplir le disque ?


    Voici un exemple pour illustrer le problème (voir également pièces jointes) :
    +le programme suivant demande en boucle des réponses et effectue :
    - une pause si la réponse est un réel
    - une nouvelle demande si la réponse n'est pas un réel
    - s'arrete seulement si la réponse est la lettre f
    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
    #!/usr/bin/perl
    use strict;
    #pattern d un reel pour les regex (desormais redondant avec $RE{num}{real} de Regexp::Common)
    my $format_reel = '[+-]?[\.]?\d+[\.]?\d*(?:[eE][+-]?\d*)?';
     
    #
    #
    # boucle infinie tant que le choix "f" n a pas ete donne
    #
    #
     
    while() {
      #saisie d un temps de pause
      print "Temps de pause ? ";
      my $choix = <STDIN>; chomp($choix);
     
      #si le choix est la lettre f => arret
      if($choix eq 'f') {
        print "\n";
        last;
      }
     
      #si le choix n est pas un reel, on redemande un nouveau choix
      elsif(not $choix =~ /^$format_reel$/) {
        print "choix \"$choix\" n est pas un reel...\n";
        next;
      }
     
      #si le choix est un reel, on fait une pause de $choix secondes
      else {
        print "pause de $choix secondes\n";
        select(undef, undef, undef, $choix);
      }
    }
     
    print "Fin..........\n";
    +le programme suivant appelle le précédent via un pipe et ne lui envoie pas la lettre f avant de fermer le pipe => affichage en boucle infinie
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #!/usr/bin/perl
    use strict;
     
    #
    # execution du script loop_pause.pl via un pipe
    #
     
    open(PIPE, "|loop_pause.pl");
    print PIPE "1\n";
    close(PIPE);
    print "apres la fermeture du pipe\n";

    merci de votre aide.
    Fichiers attachés Fichiers attachés

  2. #2
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    45
    Détails du profil
    Informations personnelles :
    Localisation : France, Morbihan (Bretagne)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 45
    Points : 29
    Points
    29
    Par défaut
    ça n'inspire personne ?

  3. #3
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Points : 12 256
    Points
    12 256
    Billets dans le blog
    1
    Par défaut
    Je n'ai rien à répondre comme ça. Je voulais tester, mais n'aurais pas le temps avant ce weekend.

  4. #4
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Le problème vient probablement du fait que, quand tu fermes le PIPE, tu fermes le fichier d'entrée de ton sous-process (son STDIN), qui se trouve alors "déconnecté" alors qu'il est en attente d'une entrée, mais tu ne tues pas le process. Tu génères au final un zombie qui boucle en erreur sur son entrée.

    As-tu essayé de mettre la condition suivante dans ta boucle while :
    (je n'ai pas fait d'essais)
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  5. #5
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    45
    Détails du profil
    Informations personnelles :
    Localisation : France, Morbihan (Bretagne)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 45
    Points : 29
    Points
    29
    Par défaut
    avec "!eof STDIN", ça fonctionne. J'ai rajouté au tout début du while le bloc suivant pour générer un affichage :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if(eof STDIN) {
      print "Fermeture du pipe!!!!\n";
      last;
    }
    et quand je lance "lancement_via_pipe.pl", on a bien l'enchainement prévu :
    debut de loop_pause.pl
    Temps de pause ? pause de 1 secondes
    Fermeture du pipe!!!!
    Fin..........
    apres la fermeture du pipe
    c'est effectivement une très bonne solution pour fiabiliser un script appelé par un pipe.

    Mais ça c'est quand on a le pouvoir de modifier le script appelé par le pipe. Imaginons maintenant que je n'ai pas le pouvoir de modifier le script "loop_pause.pl".
    J'ai essayé d'envoyer un signal d'interruption avec "print" mais le code suivant ne fonctionne pas :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    use Term::ReadKey;
    my %keys = GetControlChars;
    my $sigint = $keys{INTERRUPT};
     
    open(PIPE, "|loop_pause.pl");
    print PIPE "1\n";
    print PIPE "$sigint";
    close(PIPE);
    print "apres la fermeture du pipe\n";

  6. #6
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Tu n'as pas envoyé le signal au process. Pour envoyer un signal à un process, utilise la fonction kill (voir doc perldoc -f kill et perldoc perlipc)
    Je ne l'ai jamais fait avec un pipe, à voir si tu arrives à récupérer le numéro de process (peut-être disponible avec le file handle PIPE, voir doc de IO::Handler).

    Bon week-end
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  7. #7
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    45
    Détails du profil
    Informations personnelles :
    Localisation : France, Morbihan (Bretagne)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 45
    Points : 29
    Points
    29
    Par défaut
    bon, j'ai tenté un truc avec kill. Voici ce que j'en ai tiré :

    pour tuer mon processus, il faut que je sache si il est terminé (c'est-à-dire qu'il est en train de tourner en boucle pour rien). Il faut pas que je le tue avant qu'il ait fini de lire le PIPE et d'en avoir exécuté les ordres. C'est pour ça que j'avais un (mince) espoir d'envoyer un sigint avec une écriture "print PIPE ..." pour être sûr que le signal soit capté après en avoir fini avec tous les "print PIPE" précédents.

    Pour l'instant, je n'ai pas eu trop le choix que de scruter l'affichage (avec un fork() séparé) et d'envoyer un kill si l'affichage me remplit un fichier .log jusqu'à une limite de 100 Mo. Même si ça marche, je ne suis pas très satisfait parce que remplir un fichier texte, c'est long. Le temps d'attendre que sa taille fasse 100 Mo... et bien c'est du temps de perdu (surtout pour au final signaler à l'utilisateur que ça a buggé).

    merci tout de même pour vos retours.

  8. #8
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Et la solution d'avoir la possibilité de modifier le script appelé par un pipe ?
    Une autre idée, mais je n'ai pas de piste pour l'explorer : surveille le CPU consommé par le script appelé (appel système). Tout dépendra de l'OS sur lequel tu le fais tourner...
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  9. #9
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    45
    Détails du profil
    Informations personnelles :
    Localisation : France, Morbihan (Bretagne)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 45
    Points : 29
    Points
    29
    Par défaut
    ça marche très bien avec une surveillance de l'activité du processus (système unix => utilisation de "ps -o pid,%cpu,command"). Je vérifie que son activité est nulle pendant une vingtaine de fois d'affilée pour être sûr et c'est nickel (avec une pause de 0.25 seconde entre chaque test, ça fait une activité nulle pendant 0.25*20 = 5 secondes, ça me paraît raisonnable).

    merci beaucoup Philou67430. \o/
    ps : ça m'évite de passer par une demande de modif du script appelé par le pipe.

  10. #10
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Si tu es sous U*ix, il y a ça : Unix::Process
    Je ne sais pas ce que ça vaut.
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  11. #11
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    45
    Détails du profil
    Informations personnelles :
    Localisation : France, Morbihan (Bretagne)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 45
    Points : 29
    Points
    29
    Par défaut
    Unix:: Process semble être une simple surcouche de "ps". A voir si c'est plus pratique que la commande originale.

    Maintenant que mon problème est résolu, j'aimerais bien aller plus loin dans la compréhension de ce qui se passe quand on utilise conjointement "open(PIPE, "|...)" suivi d'un fork(). Ce que j'aimerais comprendre, c'est pourquoi le code suivant affiche en boucle (code initial de mon premier post) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #!/usr/bin/perl
    use strict;
     
    #
    # execution du script loop_pause.pl via un pipe
    #
     
    open(PIPE, "|loop_pause.pl");
    print PIPE "1\n";
    close(PIPE);
    print "apres la fermeture du pipe\n";
    Tandis que celui-ci attend sagement :
    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
    #!/usr/bin/perl
    use strict;
     
    #
    # execution du script loop_pause.pl via un pipe
    #
     
    open(PIPE, "|loop_pause.pl");
    print PIPE "1\n";
     
    #processus fils : dans cet exemple, il ne fait rien (c est ici que je fais la surveillance de l activite cpu dans mon vrai programme)
    my $pid = fork();
    if($pid == 0) {
      print "(fils) avant while\n";
      while() {
        #surveillance cpu : eventuel kill('TERM', <pid>) si %cpu == 0
      }
      print "(fils) apres while\n";
      exit;
    }
     
     
    print "(pere) avant la fermeture du pipe\n";
    close(PIPE);
    print "(pere) apres la fermeture du pipe\n";
    waitpid($pid, 0);
    print "(pere) apres waitpid\n";

  12. #12
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Dans le cas 1, tu n'as aucune instruction d'attente après ton close PIPE, dans ton cas 2, tu attends que le process fils (qui scrute le process pipé) se termine.

    Je ne comprend pas pourquoi tu n'as pas simplement mis le contenu du process que tu fork, à la suite du close PIPE (dans sans fork) ?
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  13. #13
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    45
    Détails du profil
    Informations personnelles :
    Localisation : France, Morbihan (Bretagne)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 45
    Points : 29
    Points
    29
    Par défaut
    Je suis obligé de faire le fork() avant le close(PIPE). Tout ce que je mets après le close(PIPE) n'est pas exécuté. Tu peux tester le programme 2 avec le fork() et tu constateras que l'affichage "(pere) apres la fermeture du pipe" n'apparait pas. Le close(PIPE) attend la fin du processus loop_pause.pl, or celui-ci ne rend pas la main. Le waitpid n'est pas atteint. A priori ce n'est pas le while infini du fork() qui bloque le programme.

  14. #14
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    En fait, ce qui se trouve après le close PIPE sera exécuté quand close retournera (et dans le cas d'un pipe, close attends le fin du process, qui ne finit pas dans ton cas). Donc tu as raison d'utiliser ce fork.
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

Discussions similaires

  1. [C#2.0]Problème fermeture fille Mdi
    Par SLE dans le forum Windows Forms
    Réponses: 4
    Dernier message: 02/06/2006, 14h17
  2. problème fermeture formulaire
    Par guigui5931 dans le forum Access
    Réponses: 6
    Dernier message: 03/05/2006, 11h11
  3. Problème fermeture de fenêtre
    Par jbidou88 dans le forum AWT/Swing
    Réponses: 5
    Dernier message: 26/04/2006, 17h03
  4. [VB6]problème fermeture application
    Par pimousse_cerise dans le forum VB 6 et antérieur
    Réponses: 4
    Dernier message: 20/04/2006, 11h24
  5. Problème fermeture popup
    Par nicolb dans le forum Général JavaScript
    Réponses: 5
    Dernier message: 25/02/2006, 08h53

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