7
votes

Pourquoi mon processus de parent ne voit-il pas la production de l'enfant jusqu'à ce qu'il quitte?

Considérez le script suivant:

use IO::File;
$| = 1;
my ($handle, $pid) = myPipe();
if ($pid == 0) {
  print "$$";
  sleep 5;
  exit;
}

print "child: ".<$handle>."\n";

sub myPipe {
  my $handle = new IO::File();
  my $pid = open($handle, "-|");
  return ($handle, $pid);
}


0 commentaires

3 Réponses :


3
votes

Rincer le tuyau ne se produit pas sur un calendrier fixe. Les deux seules façons que vous pouvez forcer le tuyau à rincer est en sortant du processus d'enfant (ce que vous faites maintenant) ou en appelant explicitement flush . Vous pouvez faire chasser votre poignée à Perl en effectuant l'une des opérations suivantes:

  • Ajout d'un \ n à la fin du message de l'enfant, qui fera (généralement) le tuyau chasse contre
  • réglage $ | à 1, ce qui provoque la touche de fichier actuellement sélectionnée de manière automatique
  • en utilisant io :: poignée et appelant $ gérer-> flush . .
  • en utilisant io :: gérer et réglage $ gérer-> autoflush = 1

1 commentaires

Rincer le tuyau n'est pas géré par le noyau. Le tampon est une fonction Userland!



3
votes

sur certains systèmes (la plupart?), les tuyaux utilisent des E / S Buffering par défaut. Mettre une instruction xxx

dans votre fonction mypipe fonction.

mais même lorsque la mise en mémoire tampon est éteinte, Perl ne rincent toujours pas après un nouvelle ligne. Donc, vous pouvez également vouloir que votre enfant inclure une nouvelle ligne dans la sortie.


Mise à jour: Test de votre code (Cygwin, Perl 5.10 .0, YMMV), je vois que le problème est un manque de nouvelle ligne de la sortie de l'enfant, et non si l'autoflush est explicitement allumée lorsque le tuyau est créé.


3 commentaires

Ce n'est pas tout à fait juste. Une poignée est non tamponnée (affleurante après chaque impression) si une autoflush est allumée, tamponnée à la ligne (affleurante après chaque transversale) si une autoflush est éteinte et que la poignée est ouverte sur une TTY et une touche bloquée (rinquisser lorsqu'un tampon , généralement de quelques ko, est plein) sinon.


Re: Mettre à jour - voir la réponse de Sean. La nouvelle ligne ne compte pas à cause de la mise en mémoire tampon, mais parce que le mode LIVELINE / <> dans le parent doit lire une nouvelle ligne avant de rentrer - sauf à EOF :)


@Hobbs - Merci d'avoir clarifié. Dans cet exemple particulier, l'appel à <$ gérer> dans le parent ne revient pas tant qu'il n'y a pas de nouvelle ligne dans l'entrée ou que l'entrée est fermée. Donc, la nouvelle ligne est toujours la question, mais pour une raison légèrement différente de celle que je pensais. Vous pouvez faire quelque chose de funky avec $ / , je suppose.



13
votes

Il y a deux problèmes. Premièrement, le processus de l'enfant tamponne sa production; et deuxièmement, le processus parent utilise l'opérateur code>, qui bloque jusqu'à la disponibilité d'une ligne complète ou jusqu'à la fin de fichier.

Donc, une façon d'obtenir le résultat que vous étiez S'attendre à ce que le processus d'enfant aime fermer son flux de sortie immédiatement après l'écriture: p> xxx pré>

Un autre moyen est d'ajouter une nouvelle ligne à la sortie du processus enfant, puis de rincer le flux: p> xxx pré>

Le rinçage est nécessaire car les tuyaux sont (généralement) ignorés, plutôt que des flux tamponnés sous forme de lignes lorsque des flux connectés au terminal sont généralement. P>

une troisième alternative est Pour définir le flux de sortie du processus enfant sur AUTOFLUSH: P>

if ($pid == 0) {
    $| = 1;
    print "$$\n";
    sleep 5;
    exit;
}


1 commentaires

Merci pour la réponse approfondie. J'ai réalisé plus tard que l'utilisation de <> aurait besoin d'un nouveau caractère de ligne.