【问题标题】:pipe() and fork() in cc 中的 pipe() 和 fork()
【发布时间】:2013-05-28 09:17:51
【问题描述】:

我需要创建两个子进程。一个子进程需要运行命令“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;
}

【问题讨论】:

  • 除非您是从/ 执行,否则请尝试将“bin/ls”替换为“/bin/ls”(类似于“/bin/sort”)
  • 看来您没有进行错误检查。您应该添加一些,这将有助于您诊断问题。
  • 我在子块中有 printf() 语句。没有“/”,它会显示两个子语句,但是当我输入“/”时,它不会显示这些语句;就像它没有到达儿童块一样。
  • 顺便说一句:如果路径名中没有“/”,则 execlp() 和 execvp() 执行 PATH 搜索。这都可以在 The Fine Manual 中阅读。 Thay 还可以返回(错误时)检查返回值,如果返回则 errno。
  • 这种疾病从哪里开始在字符串的开头而不是结尾打印换行符,如fprintf(stderr, "\nChild 2 Fork failed");

标签: c fork pipe


【解决方案1】:

您的父进程waits 在创建 ls 进程之前完成排序进程。

排序过程需要在完成之前读取其输入。它的输入来自直到wait 之后才会启动的ls。死锁。

您需要创建两个进程,然后为它们创建wait

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

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

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

也将所有这些应用到另一个 dup2。

然后是父进程保持管道打开的问题。我会说你应该在将管道的两端传递给孩子之后关闭父管道的两端,但是在最后一个 wait 之后,你有来自 fd[0] 的奇怪的 read ......我不知道为什么会在那里。如果ls|sort 管道运行正常,则管道之后将是空的,因此将没有任何内容可读取。无论如何,您肯定需要在父级中关闭fd[1],否则排序过程将无法完成,因为管道不会指示EOF,直到所有写入器都关闭。​​

在奇怪的read 之后是printf,它可能会崩溃,因为读取缓冲区不会被'\0' 终止。

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

【讨论】:

  • 非常感谢;我现在开始工作了。我在 dup2 之前取出了多余的关闭;在最后一个 wait() 之后,我还从 df[0] 中取出了 read()。我意识到没有必要。我在排序块内添加了一个 open(1) 语句,以便在终端中显示排序的输出,最后我完全取出了 buff 变量和最后一个 printf ,因为它们不需要。
  • 哦!我只在两个子进程之后才执行等待(NULL)。
猜你喜欢
  • 2021-12-07
  • 2012-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多