在某处C系统编程创建两个带有三个execlp小错误的管道

时间:2015-02-18 15:54:42

标签: c pipe parent-child

我正在尝试创建三个子进程和两个将执行三个execlp()的管道。但是,当我的程序运行时,输出不是我所期望的。

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    pid_t  pid = getpid();
    printf("STARTING PROCESSXXX %d\n",pid);

    int c1Toc2[2];
    int c2Toc3[2];

    if(pipe(c1Toc2) == -1)
    {
        perror("pipe");
        exit(EXIT_FAILURE);
    }
    if(pipe(c2Toc3) == -1)
    {
        perror("pipe");
        exit(EXIT_FAILURE);
    }

    int rValue = fork();

    if(rValue == -1)
    {
        perror("Child_1");
    }
    else if (rValue == 0)
    {
        printf("CHILD 1:  ");
        printf("PROCESS ID IS: %ld \tMY PARENT ID IS: %ld\trValue IS: %d\n", (long) getpid(), (long) getppid(), rValue);

        dup2(c1Toc2[1], STDOUT_FILENO);
        close(c1Toc2[0]);
        close(c2Toc3[0]);

        execlp("ps", "ps", "-ef", NULL);

        exit(0);
    }

    rValue = fork();

    if(rValue == -1)
    {
        perror("Child_2");
    }
    else if (rValue == 0)
    { 
        printf("CHILD 2:  ");
        printf("PROCESS ID IS: %ld \tMY PARENT ID IS: %ld\trValue IS: %d\n",
                (long) getpid(), (long) getppid(), rValue);

        dup2(c1Toc2[0], STDIN_FILENO);
        close(c1Toc2[1]);

        dup2(c2Toc3[1], STDOUT_FILENO);
        close(c2Toc3[0]);
        printf("CHILD 2 : goodbye\n");
        execlp("grep","grep","root",NULL);

        printf("CHILD 2 : goodbye\n");
        exit(0);
    }

    rValue = fork();

    if(rValue == -1)
    {
        perror("Child_3");
    }
    else if (rValue == 0)
    { 
        printf("CHILD 3:  ");
        printf("PROCESS ID IS: %ld \tMY PARENT ID IS: %ld\trValue IS: %d\n",
                (long) getpid(), (long) getppid(), rValue);

        dup2(c2Toc3[0], STDIN_FILENO);
        close(c2Toc3[1]);
        close(c2Toc3[0]);
        printf("CHILD 3 : \n");
        execlp("sort","sort","-n", "-k4",NULL);

        printf("CHILD 3 : goodbye\n");
        exit(0);
    }

    close(c1Toc2[1]);
    close(c1Toc2[0]);

    close(c2Toc3[1]);
    close(c2Toc3[0]);
    // Add the code for the two children  here
    sleep(3);
    printf("PARENT: PROCESS Waiting on children to complete\n");

    printf("Final Print Statement before exit\n");
    exit(0);
}

2 个答案:

答案 0 :(得分:0)

问题是你没有关闭子文件中的管道文件描述符,因此,你将它们复制到STDOUT_FILENO(例如 - grep child),即使程序已完成其常规输出,它也没有'完全退出并将EOF发布到下一个子进程(即 - 排序),这样这些孩子就会一直等待着。

我不完全确定为什么你的grep进程拒绝像正常一样退出,因为它看起来似乎是ps子退出,这应该将一个EOF发布到grep child的stdin。

这是一个可以满足您需求的版本:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
  pid_t pid = getpid();

  printf("PARENT: STARTING PROCESSXXX %d\n",pid);

  int c1Toc2[2];
  int c2Toc3[2];

  if (pipe(c1Toc2) == -1)
  {
    perror("pipe");
    exit(EXIT_FAILURE);
  }

  if (pipe(c2Toc3) == -1)
  {
    perror("pipe");
    exit(EXIT_FAILURE);
  }

  int rValue = fork();

  if (rValue == -1)
  {
    perror("Child_1");
    exit(EXIT_FAILURE);
  }
  else if (rValue == 0)
  {
    printf("CHILD 1: PROCESS ID IS: %ld \tMY PARENT ID IS: %ld\trValue IS: %d\n", (long) getpid(), (long) getppid(), rValue);

    dup2(c1Toc2[1], STDOUT_FILENO);

    close(c1Toc2[0]);
    close(c1Toc2[1]);
    close(c2Toc3[0]);
    close(c2Toc3[1]);

    execlp("ps", "ps", "-ef", NULL);
    perror("CHILD 1: execlp");
    exit(EXIT_FAILURE);
  }

  rValue = fork();

  if (rValue == -1)
  {
    perror("Child_2");
    exit(EXIT_FAILURE);
  }
  else if (rValue == 0)
  { 
    printf("CHILD 2: PROCESS ID IS: %ld \tMY PARENT ID IS: %ld\trValue IS: %d\n", (long) getpid(), (long) getppid(), rValue);

    dup2(c1Toc2[0], STDIN_FILENO);
    dup2(c2Toc3[1], STDOUT_FILENO);

    close(c1Toc2[0]);
    close(c1Toc2[1]);
    close(c2Toc3[0]);
    close(c2Toc3[1]);

    execlp("grep","grep","root",NULL);
    perror("CHILD 2: execlp");
    exit(EXIT_FAILURE);
  }

  rValue = fork();

  if (rValue == -1)
  {
    perror("Child_3");
    exit(EXIT_FAILURE);
  }
  else if (rValue == 0)
  { 
    printf("CHILD 3: PROCESS ID IS: %ld \tMY PARENT ID IS: %ld\trValue IS: %d\n", (long) getpid(), (long) getppid(), rValue);

    dup2(c2Toc3[0], STDIN_FILENO);

    close(c1Toc2[0]);
    close(c1Toc2[1]);
    close(c2Toc3[0]);
    close(c2Toc3[1]);

    execlp("sort","sort","-n", "-k4",NULL);
    perror("CHILD 3: execlp");
    exit(EXIT_FAILURE);
  }

  close(c1Toc2[0]);
  close(c1Toc2[1]);
  close(c2Toc3[0]);
  close(c2Toc3[1]);

  printf("PARENT: PROCESS Waiting on children to complete\n");
  sleep(3);
  printf("PARENT: Final Print Statement before exit\n");

  return 0;
}  

答案 1 :(得分:0)

您的代码看起来或多或少是正确的,但它似乎反映了对fork / exec和子进程管理的不完全理解。

首先,请注意除了失败之外,exec-family函数(包括execlp())不会返回。您的代码似乎另有假设。特别是,子流程不打印&#34;再见&#34;调用execlp()后的消息,除非execlp()调用失败。您应该处理execlp()确实返回的(失败)情况,但通常您会使用错误处理/错误报告代码来执行此操作。

此外,每个进程(包括父进程)都应该关闭它不会使用的文件描述符。这包括在将FD复制到其中一个标准文件号之后关闭FD,并关闭专门用于其他进程的所有文件描述符。你错过了其中几个:

  • 子级1无法关闭文件描述符c1Toc2[1](复制后)和c2Toc3[1]
  • Child 2无法关闭文件描述符c1Toc2[0]c2Toc3[1](复制后)。

此外,sleep()的父进程等待其子进程是没有意义的。如果要确保完成和/或获取退出状态,则应使用wait()waitpid()。如果它不会立即退出,那么它肯定应该使用其中一个函数,否则子进程将作为僵尸进程挂起,直到父进程退出。没有任何数量的sleep()足以确保子进程完成。另一方面,如果你不关心任何这些事情,那么你可以让父母离开。在这种情况下保持它没有特别的优势。

我不知道是否有任何一种解释了您所看到的意外行为,因为您还没有解释这是什么。