c中的pipe()和fork()

时间:2013-06-01 18:53:54

标签: c fork pipe

我需要创建两个子进程。一个孩子需要运行命令“ls -al”并将其输出重定向到下一个子进程的输入,然后该进程将对其输入数据运行命令“sort -r -n -k 5”。最后,父进程需要读取(已经排序的数据)并将其显示在终端中。终端中的最终结果(执行程序时)应该与我直接在shell中输入以下命令相同:“ls -al | sort -r -n -k 5”。为此,我需要使用以下方法:pipe(),fork(),execlp()。

我的程序编译,但我没有得到所需的输出到终端。我不知道出了什么问题。这是代码:

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

int main()
{
    int fd[2];
    pid_t ls_pid, sort_pid;
    char buff[1000];

    /* create the pipe */
    if (pipe(fd) == -1) {
        fprintf(stderr, "Pipe failed");
        return 1;
    }

    /* create child 2 first */
    sort_pid = fork();
    if (sort_pid < 0) {                         // error creating Child 2 process
        fprintf(stderr, "\nChild 2 Fork failed");
        return 1;
    }
    else if(sort_pid > 0) {                     // parent process

        wait(NULL);                             // wait for children termination

        /* create child 1 */
        ls_pid = fork();
        if (ls_pid < 0) {                       // error creating Child 1 process
            fprintf(stderr, "\nChild 1 Fork failed");
            return 1;
        }
        else if (ls_pid == 0) {                 // child 1 process
            close(1);                           // close stdout
            dup2(fd[1], 1);                     // make stdout same as fd[1]
            close(fd[0]);                       // we don't need this end of pipe
            execlp("bin/ls", "ls", "-al", NULL);// executes ls command
        }

        wait(NULL);
        read(fd[0], buff, 1000);                // parent reads data 
        printf(buff);                           // parent prints data to terminal   
    }
    else if (sort_pid == 0) {                   // child 2 process
        close(0);                               // close stdin
        dup2(fd[0], 0);                         // make stdin same as fd[0]
        close(fd[1]);                           // we don't need this end of pipe
        execlp("bin/sort", "sort", "-r", "-n", "-k", "5", NULL); // executes sort operation
    }

    return 0;
}

1 个答案:

答案 0 :(得分:3)

您的父进程wait用于在创建ls进程之前完成排序过程。

排序过程需要先读取输入才能完成。它的输入来自于wait之后才会开始的ls。死锁。

您需要创建两个流程,然后为wait创建两个流程。

此外,您的文件描述符操作不太正确。在这对电话中:

close(0);
dup2(fd[0], 0);

关闭是多余的,因为如果存在,dup2将自动关闭现有的fd 0。您应该在dup2之后执行close(fd[0]),因此您只有一个文件描述符绑定到管道的那一端。如果你想要非常健壮,你应该已经测试了fd[0]==0,并且在这种情况下跳过dup2并关闭。

也将所有这些应用到其他dup2。

然后是打开管道的父进程的问题。我说你应该把它们传递给孩子后关闭父母的管道的两端,但是在最后read之后你从fd[0]得到了奇怪的wait ......我不确定为什么会这样。如果ls|sort管道已正确运行,则管道将在之后为空,因此无需读取任何内容。在任何情况下,您肯定需要在父级中关闭fd[1],否则排序过程将无法完成,因为管道将不会在所有编写器关闭之前指示EOF。

奇怪的readprintf之后可能会崩溃,因为读取缓冲区不会'\0' - 终止。

使用execlp的重点是它为您执行$PATH查找,因此您无需指定/bin/。我的第一次测试运行失败,因为我的排序位于/usr/bin/。为什么不需要硬编码路径?