【问题标题】:How to chain multiple pipes? (plus weird buggs)如何链接多个管道? (加上奇怪的虫子)
【发布时间】:2016-11-19 18:09:47
【问题描述】:

我正在尝试编写一个可以处理管道命令的简单外壳。我希望能够处理所有链接在一起的多个管道,但我很难弄清楚如何实现这样的东西。

这是我目前的尝试:

int status;
    int lastToken = 0;
    int pipe_pid;

    //create the pipes
    int pipefd[pipes][2];

    // Loop to run all commands in the vertical list.
    while(1){
        if (c->type == TOKEN_PIPE){

        // Here is where we deal with pipes
            for (int i = 0; i < pipes; i++){
                pipe(pipefd[i]);

                pipe_pid = fork();

                //this is a receiving pipe
                if (pipe_pid == 0){
                    // create the write end of the pipe
                    dup2(pipefd[i][WRITE_SIDE], STDOUT_FILENO);
                    close(pipefd[i][READ_SIDE]);
                    close(pipefd[i][WRITE_SIDE]);
                    execvp(c->argv[0], c->argv);
                    // printf("parent pipe\n");
                }
                //this is a writing pipe
                else{
                    close(pipefd[i][WRITE_SIDE]);
                    dup2(pipefd[i][READ_SIDE], STDIN_FILENO);
                    close(pipefd[i][READ_SIDE]);
                    // printf("child pipe\n");
                }
            }



        // This stuff happens for all commands
        lastToken = c->type;
        // If it's the last command, we're done
        if (c->next == NULL){
            break;
        }
        else{
            c = c->next;
        }
    }

命令在链表中链接在一起,c是我的命令指针

pipes 是我在解析字符串时创建的变量,所以我知道有多少 '|'我在命令中看到了。这应该告诉我需要分叉的子进程的数量。

我使用管道为管道描述符创建一个二维数组。

然后我想循环遍历管道并为每个分叉一次,并使用 dup2 映射输入和输出。

我遇到了我无法弄清楚的不一致错误。首先,每次我运行管道命令时,我的 shell 都会立即崩溃,没有段错误或其他打印错误。

其次,如果我运行像echo foo | wc -c 这样的命令,我有时会得到 4,有时会得到 0 作为输出。

我确定我只是在做一些愚蠢的事情,但我不确定是什么:/

【问题讨论】:

  • 想想你在做什么——对于n进程,你需要在它们之间使用n-1管道。您正在创建 n 进程和 n 管道,因此您有一个额外的管道。
  • @ChrisDodd 我想我实际上有 n -1 个进程,我确定pipes 值的方式是通过计数'|'令牌,所以它应该是正确的......

标签: c shell pipe fork pipeline


【解决方案1】:

我发现我做错了什么,我在所有线程完成使用它们之前关闭了管道。我通过撤出关闭电话来修复它。

// writing side of the pipe
if (c->type == TOKEN_PIPE){
    close(c->pipefd[READ_SIDE]);
    dup2(c->pipefd[WRITE_SIDE], STDOUT_FILENO);

}
// receiving side of the pipe
if (commandPrev->type == TOKEN_PIPE){
    close(commandPrev->pipefd[WRITE_SIDE]);
    dup2(commandPrev->pipefd[READ_SIDE], STDIN_FILENO);

}

然后在父线程中,就在我收割我的僵尸之前,我检查已完成使用的管道并关闭它们。

    // writing side of the pipe
    if (c->type == TOKEN_PIPE){
        close(c->pipefd[READ_SIDE]);
        dup2(c->pipefd[WRITE_SIDE], STDOUT_FILENO);
    }
    // receiving side of the pipe
    if (commandPrev->type == TOKEN_PIPE){
        close(commandPrev->pipefd[WRITE_SIDE]);
        dup2(commandPrev->pipefd[READ_SIDE], STDIN_FILENO);
    close(commandPrev->pipefd[READ_SIDE]);

我不确定这是否是最佳方法,但它对我来说没有错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-01
    • 1970-01-01
    • 2019-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-08
    相关资源
    最近更新 更多