Pregunta

Este código a continuación es para ejecutar ls -l | wc -l. En el código, si comento close (p [1]) en parent entonces el programa simplemente se cuelga, esperando alguna entrada. ¿Por qué es así? El hijo escribe la salida de ls en p1 y el padre debería haber tomado esa salida 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);
    }
}
¿Fue útil?

Solución

pipe + fork crea 4 descriptores de archivo, dos son entradas

Antes de la bifurcación, tiene una sola tubería con una entrada y una salida.

Después de la bifurcación, tendrá una sola tubería con dos entradas y dos salidas.

Si tiene dos entradas para la tubería (en las que escribe un proceso) y dos salidas (de las que lee un proceso), debe cerrar la otra entrada o el lector también tendrá una entrada de tubería que nunca se cierra.

En su caso, el padre es el lector, y además del extremo de salida de la tubería, tiene un otro extremo abierto, o extremo de entrada, de la tubería que podría, en teoría , ser escrito a. Como resultado, la tubería nunca envía un eof, porque cuando el niño sale, la tubería todavía está abierta debido a la fd no utilizada de los padres.

Así que los padres se estancan, esperando para siempre que se escriba a sí mismo.

Otros consejos

Tenga en cuenta que ' dup (p [1]) ' significa que tiene dos descriptores de archivo que apuntan al mismo archivo. No cierra p [1] ; deberías hacer eso explícitamente. Del mismo modo con ' dup (p [0]) '. Tenga en cuenta que la lectura de un descriptor de archivo de una tubería solo devuelve cero bytes (EOF) cuando no hay descriptores de archivo de escritura abiertos para la tubería; hasta que se cierre el último descriptor de escritura, el proceso de lectura se suspenderá indefinidamente. Si dup () el final de la escritura, hay dos descriptores de archivo abiertos para el final de la escritura, y ambos deben cerrarse antes de que el proceso de lectura tenga EOF.

Tampoco necesita ni desea la llamada wait () en su código. Si la lista ls es más grande de lo que puede contener una tubería, sus procesos se estancarán, con el niño esperando a que ls se complete y ls esperando que el niño continúe leyendo los datos que ha escrito.

Cuando se elimina el material redundante, el código de trabajo se convierte en:

#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);
}

En Solaris 10, esto se compila sin previo aviso con:

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

Si el hijo no cierra p [1] , entonces ese FD está abierto en dos procesos: padre e hijo. El padre finalmente lo cierra, pero el niño nunca lo hace, por lo que el FD permanece abierto. Por lo tanto, cualquier lector de ese FD (el niño en este caso) esperará para siempre solo en caso de que se escriba más sobre él ... ¡no lo es, pero el lector simplemente NO SABE! -)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top