管道:在管道数组中关闭文件描述符

时间:2019-03-17 15:00:28

标签: c linux pipe system-calls

我现在正在为系统编程课程学习Linux和类似的东西,现在我很难理解关闭管道数组中的文件描述符。

 // write the code to loop over the command line arguments (remember to skip the executable name)
for (int i = 1; i < argc; i++) {
    // call pipe before we fork
    if ((pipe(pipe_fd[i-1])) == -1) {
        perror("pipe");
        exit(1);
    }
    // call fork
    int result = fork();
    if (result < 0) {   // case: a system call error
        // handle the error
        perror("fork");
        exit(1);
    } else if (result == 0) {  // case: a child process
        // child does their work here
        // child only writes to the pipe so close reading end
        if (close(pipe_fd[i-1][0]) == -1) {
            perror("close reading end from inside child");
            exit(1);
        }
        // before we forked the parent had open the reading ends to
        // all previously forked children -- so close those
        int child_no;
        for (child_no = 0; child_no < i-1; child_no++) {
            if (close(pipe_fd[child_no][0]) == -1) {
                perror("close reading ends of previously forked children");
                exit(1);
            }
        }
        int len = strlen(argv[i]);
        // write len to the pipe as an integer
        if (write(pipe_fd[i-1][1], &len, sizeof(int)) != sizeof(int)) {
            perror("write from child to pipe");
            exit(1);
        }
        // I'm done with the pipe so close it
        if (close(pipe_fd[i-1][1]) == -1) {
            perror("close pipe after writing");
            exit(1);
        }
        // exit so I don't fork my own children on next loop iteration
        exit(0);
    } else {
        // in the parent but before doing the next loop iteration
        // close the end of the pipe that I don't want open
        if (close(pipe_fd[i-1][1]) == -1) {
            perror("close writing end of pipe in parent");
            exit(1);
        }
    }
}

我将列出我现在所了解的内容:

  1. 我了解父子进程需要关闭不需要使用的fds,在这种情况下,子进程正在写给父进程,因此父进程需要关闭写入端口,而子进程需要关闭读取端口。
  2. 我了解文件描述符在父进程和子进程之间共享。

上面的代码是从我的演讲幻灯片中给出的,我对此感到特别困惑。

在循环中,我观察到每个孩子都被fork创建后关闭了其读取端口,执行此操作的代码是:

else if (result == 0) {  // case: a child process
    // child does their work here
    // child only writes to the pipe so close reading end
    if (close(pipe_fd[i-1][0]) == -1) {
        perror("close reading end from inside child");
        exit(1);
    }

据我目前的理解,每个孩子在被叉子分娩后都将关闭自己的阅读端口,我认为后者的孩子应该不用担心关闭前一个孩子的阅读端口。

但是,在我阅读以下代码后,我的理解似乎并不正确:

        // before we forked the parent had open the reading ends to
    // all previously forked children -- so close those
    int child_no;
    for (child_no = 0; child_no < i-1; child_no++) {
        if (close(pipe_fd[child_no][0]) == -1) {
            perror("close reading ends of previously forked children");
            exit(1);
        }
    }

我不明白后一个孩子为什么要去关闭前一个孩子的阅读端口,一旦创建了这些孩子,这些阅读端口就已经关闭了吗?

感谢您的帮助。 :)

1 个答案:

答案 0 :(得分:0)

直到打开描述符的所有进程都将其关闭,描述符才真正关闭。由于每个孩子都继承了上一个进程的所有管道描述符,因此他们应该关闭所有未使用的管道描述符。

关闭读取端口的主要原因是,如果在退出读取器之后尝试写入管道,则写入过程将收到错误或信号。如果其他孩子将所有读取端口保持打开状态,则直到所有后续孩子退出后,这种情况才会发生。