Pergunta

Este código abaixo é para ls execução -l | wc -l. No código, se eu comentar close (p [1]) no pai então o programa só trava, à espera de alguma entrada. Por que é assim? A criança escreve saída de ls em p1 e pai deveria ter tomado que a saída 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);
    }
}
Foi útil?

Solução

pipe + fork cria 4 descritores de arquivos, dois são entradas

Antes do garfo você tem um único tubo com uma entrada e uma saída.

Depois do garfo, você terá um único tubo com duas entradas e duas saídas.

Se você tem duas entradas para o tubo (que uma proc escreve) e duas saídas (que uma proc lê), você precisa fechar a outra entrada ou o leitor também terá uma entrada de tubo que nunca fica fechada.

No seu caso o pai é o leitor, e para além da extremidade do tubo de saída, tem um aberto outra extremidade , ou no final de entrada, do tubo que o material poderia, em teoria , ser gravado. Como resultado, o tubo nunca envia um EOF, porque quando a criança sai do tubo ainda está em aberto devido a fd não utilizado do pai.

Assim, os impasses pais, esperando para sempre para que ele escreve para si mesmo.

Outras dicas

Observe que o dup(p[1]) 'significa que você tem dois descritores de arquivos que apontam para o mesmo arquivo. Ele não fecha p[1]; você deve fazer isso explicitamente. Da mesma forma com 'dup(p[0])'. Note-se que uma leitura descritor de arquivo de um cano só retorna zero bytes (EOF) quando não há descritores de arquivos de gravação em aberto para o tubo; até o último descritor gravação é fechado, o processo de leitura irá travar indefinidamente. Se você dup() final de gravação, há dois descritores de arquivos abertos para o final de gravação, e ambos devem ser fechadas antes de o processo de leitura recebe EOF.

Você também não precisa ou quer a chamada wait() em seu código. Se o ls lista é maior do que um tubo pode segurar, seus processos vai impasse, com a criança à espera de ls de espera completa e ls para a criança a continuar com a leitura dos dados que tem escrito.

Quando o material redundante é retirado, o código de trabalho torna-se:

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

No Solaris 10, Isso compila sem aviso com:

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

Se a criança não fecha p[1], então isso FD está aberto em dois processos - pai e filho. O pai, eventualmente, fecha-lo, mas a criança nunca faz - de modo que o FD permanece aberto. Portanto, qualquer leitor que FD (a criança, neste caso) vai esperar para sempre apenas no caso de mais de escrever que vai ser feito sobre ele ... não é, mas o leitor só não sabe! -)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top