使用pipe()系统调用

时间:2011-10-07 20:46:04

标签: c posix piping

我一直在尝试使用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 个答案:

答案 0 :(得分:6)

您必须关闭不使用的管道。 至少sort将从stdin读取,直到stdin关闭。

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

    ls孩子中的
  • filedes [0](这可能会在ls结束时关闭)
  • 在父程序中
  • filedes [0](这种情况永远不会因为waitpid()因为排序结束而关闭,但它永远不会因为父节点的stdin保持打开而停止)

将您的计划更改为

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]);
}

答案 1 :(得分:4)

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

    filedes[0]
  • pid_afiledes[1]
  • pid_b
  • 父进程中的filedes[0]filedes[1]

您还应检查pipe()fork()是否未返回-1,这意味着发生了错误。

答案 2 :(得分:3)

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

答案 3 :(得分: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;
    }