在C语言中关闭管道文件描述符

7

以下是代码:

int main() {

    int fd[2];
    pipe(fd);
    int r = fork();
    if (r > 0) { //parent
        close(fd[0]);
        // do a bunch of things
    } else { //child
        close(fd[1]);
        // do a bunch of things
    return 0;
}

这是一段代码,其中父进程向管道写入数据,子进程从管道读取数据。我的问题是:对于两个close语句,它们到底关闭了什么?父进程和子进程应该共享同一个文件,即fd [0]和fd [1]。如果在父进程中关闭了fd [0],那么子进程中也应该关闭它吗?


每个 fd 都是管道的一个端口。 - Jonathon Reinhart
3个回答

6
http://linux.die.net/man/2/pipe中可以看到,pipe()创建一个管道,由两个文件描述符组成,分别对应管道的两端,即读端和写端。它并不是一个真正的文件。内核从写端读取数据,为您进行缓冲,并将其传输到读端。
这就很容易理解为什么pipe()会创建两个文件描述符。写程序将所有需要的数据写入写文件描述符并关闭该文件描述符。这也会触发发送EOF。读程序通常会一直读取数据,直到遇到EOF并关闭其端口。在这种情况下,有一段时间写文件描述符已经关闭,但数据仍然在管道中缓存,等待读程序读出。如果只有一个文件描述符,那么在写程序和读程序之间需要另一层协调,否则谁来关闭,何时关闭?

那么在 fork 之后,管道就有四个端口了吗? - Xufeng
1
@Xufeng 不是的,在fork之后,管道会在父进程和子进程之间共享。你需要自行决定父进程使用写端还是读端,反之亦然。 - congusbongus
父进程和子进程共享两端吗?如果是这样,为什么在一个进程中关闭一个端口不会影响另一个进程中的同一端口?或者close()并没有真正关闭端口,它只是关闭了进程与该端口之间的连接? - Xufeng
3
两个进程将拥有不同的文件描述符表,因此当您在一个进程中关闭描述符时,它会从相应的文件描述符表中删除。 - prince
@Xufeng 阐述一下Prince所说的(他是正确的),管道及其“结束”与进程是分开存在的。你可以用fopenfork做类似的事情:父子进程原则上可以读写同一个文件,虽然这可能会很危险,而且你永远不需要这样做。 - congusbongus

3

pipe()调用总是返回一个整数数组,其中数组的第一个元素是从管道读取的读描述符,第二个元素是写入到管道中的写描述符。管道提供单向通信。如果您在父进程中关闭了fd[0],并且在子进程中也关闭了它,则无论如何都不能从管道中读取数据;反之亦然,如果在这两个进程中都关闭了fd[1],则不能将数据写入管道中。因此,在一个进程中关闭读描述符,以便该进程只能写入数据,而另一个进程将关闭写描述符,使其只能从管道中读取数据。


0

由于您在创建管道后进行了分叉,因此现在您有两个管道可供使用。实际上,您应该将管道视为单向通信线路,通过分叉它,您现在拥有了双向通信线路。但仍然是两个不同的管道,因此为了给信息流指定方向,您需要相应地关闭端口。

编辑: ps:当考虑到一个连接两个进程的管道如何工作时,这种观点非常有效。如果您发现自己正在处理多个管道,请稍微调整我之前提出的概念,但它仍然基本有效。这应该会有所帮助


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接