Question

Ce code ci-dessous est destiné à l'exécution de ls -l | wc -l. Dans le code, si je commente close (p [1]) dans parent, le programme se bloque, dans l'attente d'une entrée. Pourquoi c'est comme ça? L'enfant écrit la sortie de ls sur p1 et le parent devrait l'avoir prise de p0.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

main ()
{
  int i;
  int p[2];
  pid_t ret;
  pipe (p);
  ret = fork ();

  if (ret == 0)
    {
      close (1);
      dup (p[1]);
      close (p[0]);
      execlp ("ls", "ls", "-l", (char *) 0);
    }

  if (ret > 0)
    {
      close (0);
      dup (p[0]);
      //Doubt, Commenting the line below does not work WHy?
      close (p[1]);
      wait (NULL);
      execlp ("wc", "wc", "-l", (char *) 0);
    }
}
Était-ce utile?

La solution

pipe + fork crée 4 descripteurs de fichier, dont deux sont des entrées

Avant la fourche, vous avez un seul tuyau avec une entrée et une sortie.

Après la fourche, vous aurez un seul tuyau avec deux entrées et deux sorties.

Si vous avez deux entrées pour le tuyau (qu'un proc écrit dans) et deux sorties (dans lesquelles un proc lit), vous devez fermer l'autre entrée ou le lecteur aura également une entrée de tuyau qui ne sera jamais fermée.

Dans votre cas, le parent est le lecteur et, en plus de l'extrémité de sortie du tuyau, il a une autre extrémité ouverte, ou extrémité d'entrée du tuyau, ce qui pourrait, en théorie, , être écrit à. De ce fait, le canal n’envoie jamais d’eof, car lorsque le fils quitte le canal, le canal est toujours ouvert en raison du fd inutilisé du parent.

Le parent bloque alors, attendant pour toujours de s’écrire.

Autres conseils

Notez que ' dup (p [1]) ' signifie que vous avez deux descripteurs de fichier pointant vers le même fichier. Il ne ferme pas p [1] ; vous devriez le faire explicitement. De même avec ' dup (p [0]) '. Notez qu'un descripteur de fichier lu dans un canal ne renvoie que zéro octet (EOF) lorsqu'il n'y a pas de descripteur de fichier en écriture ouvert pour le canal; jusqu'à ce que le dernier descripteur d'écriture soit fermé, le processus de lecture sera suspendu indéfiniment. Si vous dup () la fin de l'écriture, il y a deux descripteurs de fichier ouverts à la fin de l'écriture, et les deux doivent être fermés avant que le processus de lecture obtienne EOF.

Vous n'avez également pas besoin ou ne souhaitez pas l'appel wait () dans votre code. Si la liste ls est plus grande qu'un canal ne peut contenir, vos processus seront bloqués, l'enfant attendra que ls soit terminé et ls en attente de l'enfant à lire les données qu'il a écrites.

Lorsque le contenu redondant est supprimé, le code de travail devient:

#include <unistd.h>

int main(void)
{
    int p[2];
    pid_t ret;
    pipe(p);
    ret = fork();

    if (ret == 0)
    {
        close(1);
        dup(p[1]);
        close(p[0]);
        close(p[1]);
        execlp("ls", "ls", "-l", (char *) 0);
    } 
    else if (ret > 0)
    {
        close(0);
        dup(p[0]);
        close(p[0]);
        close(p[1]);
        execlp("wc", "wc", "-l", (char *) 0);
    }
    return(-1);
}

Sous Solaris 10, cette opération est compilée sans avertissement avec:

Black JL: gcc -Wall -Werror -Wmissing-prototypes -Wstrict-prototypes -o x x.c
Black JL: ./x
      77
Black JL:

Si l'enfant ne ferme pas p [1] , ce FD est ouvert dans deux processus - parent et enfant. Le parent le ferme par la suite, mais l'enfant ne le fait jamais - le FD reste donc ouvert. Par conséquent, tout lecteur de cette FD (l'enfant dans ce cas) va attendre pour toujours au cas où plus d'écriture serait faite dessus ... ce n'est pas, mais le lecteur ne SAIT PAS! -)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top