5

我一直在尝试使用 pipe() 系统调用来创建一个支持管道的 shell(使用任意数量的命令)。

不幸的是,我在使用 pipe() 时运气不佳。在花了几天时间查看各种在线资源之后,我决定编写一个与执行效果相同的过于简化的程序,ls | sort看看我是否可以让管道为两个兄弟、子进程工作。这是代码:

#include <sys/wait.h>
#include <unistd.h>

void run(char *cmd) {
   char *args[2];
   args[0] = cmd;
   args[1] = NULL;

   execvp(cmd, args);
}

int main(void) {
    int filedes[2];
    pipe(filedes);

    pid_t pid_a, pid_b;

    if (!(pid_a = fork())) {
        dup2(filedes[1], 1);
        run("ls");
    }

    if (!(pid_b = fork())) {
        dup2(filedes[0], 0);
        run("sort");
    }

    waitpid(pid_a, NULL, 0);
    waitpid(pid_b, NULL, 0);

    return 0;
}

管道是在父进程中创建的,我知道在 execvp() 调用之后,每个子进程都会继承 pipe() 在父进程中创建的文件描述符。对于该ls过程,我使用 dup2() 将其标准输出 (1) 重定向到管道的写入端,对于该sort过程,标准输入 (0) 被重定向到管道的读取端。

最后,我等待两个进程完成后再退出。

我的直觉告诉我这应该有效,但事实并非如此!

有什么建议么?

4

4 回答 4

6

您必须关闭不使用的管道。至少sort会从它的标准输入读取,直到标准输入关闭。

在这种情况下,它的标准输入永远不会关闭,因为您仍然有 2 个打开的文件描述符。

  • ls 子项中的filedes[0](这可能会在 ls 完成时关闭)
  • 父程序中的filedes [0](当您等待pid()结束排序时,它永远不会关闭,但它永远不会因为父程序保持其标准输入打开)

将您的程序更改为

if (!(pid_a = fork())) {
    dup2(filedes[1], 1);
    closepipes(filedes);
    run("ls");
}

if (!(pid_b = fork())) {
    dup2(filedes[0], 0);
    closepipes(filedes);
    run("sort");
}
closepipe(filedes);
waitpid(pid_a, NULL, 0);
waitpid(pid_b, NULL, 0);

closepipes 类似于

void closepipes(int *fds)
{ 
 close(fds[0]);
 close(fds[1]);
}
于 2011-10-07T21:03:17.023 回答
4

在调用waitpid父进程之前,您必须关闭管道中不需要的所有文件描述符。这些都是:

  • filedes[0]pid_a
  • filedes[1]pid_b
  • 在父进程filedes[0]filedes[1]

您还应该检查它pipe()并且fork()没有返回-1,这意味着发生了错误。

于 2011-10-07T21:10:17.943 回答
3

您需要(至少)关闭父进程中管道的写入端。否则,管道的读取端永远不会读取 EOF 状态,并且sort永远不会完成。

于 2011-10-07T20:59:46.447 回答
1

此代码正常工作...

    #include <sys/wait.h>
    #include <unistd.h>
    using namespace std;

    void run(char *cmd) {
       char *args[2];
       args[0] = cmd;
       args[1] = NULL;

       execvp(cmd, args);
    }
    void closepipe(int *fds)
    { 
     close(fds[0]);
     close(fds[1]);
    }

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

        int filedes[2];
        pipe(filedes);
        char lss[]="ls";
        char sorts[]="sort";
        pid_t pid_a, pid_b;
     chdir(argv[1]);
    if (!(pid_a = fork())) {
        dup2(filedes[1], 1);
        closepipe(filedes);
        run(lss);
    }

    if (!(pid_b = fork())) {
        dup2(filedes[0], 0);
        closepipe(filedes);
        run(sorts);
    }
    closepipe(filedes);
    waitpid(pid_a, NULL, 0);
    waitpid(pid_b, NULL, 0);

        return 0;
    }
于 2012-09-06T13:42:33.183 回答