【问题标题】:Program stuck on Pipe (exec ls grep sort)程序卡在管道上(exec ls grep sort)
【发布时间】:2015-06-13 19:50:09
【问题描述】:

我正在尝试制作一个执行以下命令的程序,该命令使用管道将一个的输出连接到下一个的输入,并采用两个参数 DIR(目录)和 ARG(文件类型,例如:jpg)。

ls DIR -laR | grep ARG |排序

代码如下:

int main(int argc, char *argv[]) {

    if (argc != 3) {
        printf("Invalid arguments. <dir> <arg>\n");
        exit(1);
    }

    int pipe_fd1[2];
    int pipe_fd2[2];
    pid_t ls_pid, grep_pid;
    int status;

    pipe(pipe_fd1);
    pipe(pipe_fd2);

    ls_pid = fork();
    if (ls_pid == 0) { //first child ls DIR -laR
        dup2(pipe_fd1[1], STDOUT_FILENO);
        close(pipe_fd1[0]);

        execlp("ls", "ls", argv[1], "-laR", NULL);

    } else if (ls_pid > 0) {
        grep_pid = fork();
        if (grep_pid == 0) { //second child grep ARG
            dup2(pipe_fd1[0], STDIN_FILENO);
            dup2(pipe_fd2[1], STDOUT_FILENO);       
            close(pipe_fd1[1]);
            close(pipe_fd2[0]);

            waitpid(ls_pid, &status, 0);    
            execlp("grep", "grep", argv[2], NULL);

        } else if (grep_pid > 0) { //parent sort
            dup2(pipe_fd2[0], STDIN_FILENO);
            close(pipe_fd2[1]);

            waitpid(grep_pid, &status, 0);
            execlp("sort", "sort", NULL);
        }

    }

    return 0;
}

好像卡住了?不知道为什么?

【问题讨论】:

  • 为什么在调用sort之前要等待grep终止?
  • 在我的系统上,程序卡在waitpid(grep_pid, &amp;status, 0); 线上,因为grep 永远不会终止。为什么不关闭父进程中与第一个管道关联的文件描述符?

标签: c linux pipe fork dup2


【解决方案1】:

你永远不会在父节点上关闭pipe_fd1,所以grepsort 不知道何时停止读取输入:因为管道读写端永远不会在父节点上关闭,读取器阻塞等待更多永远不会到达的输入。你需要关闭它。

此外,您不需要waitpid():管道的工作方式可确保输入在整个管道中线性且有序地流动。

这是解决了这些问题的工作版本:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(int argc, char *argv[]) {

    if (argc != 3) {
        printf("Invalid arguments. <dir> <arg>\n");
        exit(1);
    }

    int pipe_fd1[2];
    int pipe_fd2[2];
    pid_t ls_pid, grep_pid;

    pipe(pipe_fd1);

    ls_pid = fork();
    if (ls_pid == 0) { //first child ls DIR -laR
        dup2(pipe_fd1[1], STDOUT_FILENO);
        close(pipe_fd1[0]);
        execlp("ls", "ls", argv[1], "-laR", NULL);

    } else if (ls_pid > 0) {
        dup2(pipe_fd1[0], STDIN_FILENO);
        close(pipe_fd1[1]);

        pipe(pipe_fd2);
        grep_pid = fork();

        if (grep_pid == 0) { //second child grep ARG
            dup2(pipe_fd2[1], STDOUT_FILENO);
            close(pipe_fd2[0]);  
            execlp("grep", "grep", argv[2], NULL);

        } else if (grep_pid > 0) { //parent sort
            dup2(pipe_fd2[0], STDIN_FILENO);
            close(pipe_fd2[1]);
            execlp("sort", "sort", NULL);
        }

    }

    return 0;
}

【讨论】:

  • 感谢您的帮助,但我不明白为什么当我从未在父级上使用 pipe_fd1 进行任何重定向时,父级需要关闭 pipe_fd1
  • @0kazaki 因为只要管道中至少有一个写入器,读取器进程将永远不会看到输入结束,即使该写入器(父级)实际上没有写。当最后一个 writer 关闭管道时,读者会看到输入结束并继续(sort 需要在显示结果之前消耗所有输入)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-02-02
  • 2017-05-20
  • 1970-01-01
  • 1970-01-01
  • 2013-08-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多