为什么waitpid被这种特殊情况阻止了?

时间:2019-04-06 13:08:18

标签: c

我想了解管道的工作原理,但是我不明白为什么在用“ ls -l / usr / bin”和“ grep ls”执行我的程序的情况下,waitpid会被阻塞。...选项-l可行! my_str_tab只是将字符串的每个单词放入charstar数组中。

void command_levels(int *pipe_fd, char **av, int idx, int pipe_save, int pipe_one)
{
    if (idx == 1)
        dup2(pipe_fd[1], 1);
    else if (idx > 1 && av[idx + 1] != NULL) {
        dup2(pipe_save, 0);
        dup2(pipe_fd[1], 1);
    }
    if (idx > 1 && av[idx + 1] == NULL) {
        dup2(pipe_save, 0);
        dup2(pipe_one, 1);
    }
}

void multiple_pipe_handle(char **av, char **env, int idx, int pipe_one)
{
    int pipe_fd[2] = {0, 0};
    char **command = NULL;
    static int pipe_save = 0;

    if (av[idx] == NULL)
        return;
    command = my_str_tab(av[idx], " ");
    pipe(pipe_fd);
    command_levels(pipe_fd, av, idx, pipe_save, pipe_one);
    if (fork() == 0) {
        close(pipe_fd[0]);
        close(pipe_fd[1]);
        execve(command[0], command, env);
    } else {
        wait(NULL);
        close(pipe_fd[1]);
        pipe_save = pipe_fd[0];
        multiple_pipe_handle(av, env, idx + 1, pipe_one);
        close(pipe_fd[0]);
    }
}

int main(int ac, char **av, char **env)
{
    int pipe_one = dup(1);

    multiple_pipe_handle(av, env, 1, pipe_one);
}

我希望所有单词的输出都包含“ ls”,但我处于无限循环中。.

1 个答案:

答案 0 :(得分:2)

这是实现管道时的常见错误。

-l传递给ls时,与不传递该选项时相比,它产生的输出更多。这使其完全填满管道的内部缓冲区。内核“阻止”它继续执行,直到从管道的另一端读取某些内容为止。但是,管道的另一端尚未读取任何内容,因为您的父程序在开始ls进程之前正在等待grep完成执行。但是ls将无法完成执行,直到它可以向管道中写入更多数据,因此整个程序将陷入僵局。

要修复此错误,必须先等待管道中所有进程的 all ,然后再等待其中的任何。您不能通过对multiple_pipe_handle的单个递归调用来做到这一点。您需要两个循环,一个循环调用fork,一个循环调用waitpid,以及一个子进程PID数组。如果您打算从父流程中最终管道流程的输出中读取数据,则必须在开始之前读取所有产生的数据(直到read通过返回零字节数据表示EOF信号)呼叫waitpid