使用pipe()系统调用

Aar*_*ron 5 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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

有什么建议?

nos*_*nos 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);
Run Code Online (Sandbox Code Playgroud)

closepipes就像是

void closepipes(int *fds)
{ 
 close(fds[0]);
 close(fds[1]);
}
Run Code Online (Sandbox Code Playgroud)


Rol*_*lig 4

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

  • filedes[0]pid_a
  • filedes[1]pid_b
  • 两者filedes[0]以及filedes[1]在父进程中

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