为什么在读取和写入管道时需要关闭fds?

10 c c++ unix multithreading pipe

这是一个例子来说明我的意思:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main(void)
{
        int     fd[2], nbytes;
        pid_t   childpid;
        char    string[] = "Hello, world!\n";
        char    readbuffer[80];

        pipe(fd);

        if((childpid = fork()) == -1)
        {
                perror("fork");
                exit(1);
        }

        if(childpid == 0)
        {
                /* Child process closes up input side of pipe */
                close(fd[0]);

                /* Send "string" through the output side of pipe */
                write(fd[1], string, (strlen(string)+1));
            exit(0);
    }
    else
    {
            /* Parent process closes up output side of pipe */
            close(fd[1]);

            /* Read in a string from the pipe */
            nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
            printf("Received string: %s", readbuffer);
    }

   return(0);
Run Code Online (Sandbox Code Playgroud)

}

但是,如果我的一个进程需要连续写入管道而另一个管道需要读取,该怎么办?

上面的例子似乎只适用于一次写入和一次读取.

Bea*_*ano 25

您的管道是单向流 - 每端都有一个文件描述符.没有必要关闭()管道的任何一端以允许数据沿其传递.

如果您的管道跨越进程(即在fork()之前创建,然后父级和子级使用它进行通信),您可以有一个写入和一个读取结束.然后,最好关闭管道的不需要的末端.这将

  • 确保当写入端关闭管道时,读取端会看到它.举个例子,假设孩子是写作方,它就会死掉.如果父写入端尚未关闭,则父级将不会从管道获得"eof"(零长度read()) - 因为管道具有打开的写入端.
  • 明确哪个进程正在写入以及哪个进程正在对管道进行读取.

如果您的管道跨越线程(在同一过程中),则不要关闭管道的不需要的末端.这是因为文件描述符由进程保存,并且为一个线程关闭它将为所有线程关闭它,因此管道将变得不可用.

没有什么可以阻止你让一个进程连续写入管道和另一个进程读取.如果这是一个问题,那么你可以给我们更多的细节来帮助你.

  • 如果您处于线程环境中,则各种线程共享文件描述符.所以在这些情况下,在完成之前不要关闭管道的读/写端,否则管道将关闭.我现在明白了这个问题 - 当管道跨越进程时,当管道跨越线程(在进程内)时关闭不需要的末端,因此不要关闭不需要的末端. (4认同)

Dav*_*eas 11

执行fork后,所有fds都重复.每个过程都打开管道的两端.如果您只想使用一端,则应关闭另一端(如果您的进程写入,请关闭读取端).

除了明显的事实,如果你不关闭描述符,操作系统将在打开的文件表中保留额外的条目,如果你没有关闭管道的写端,读者永远不会收到EOF,因为还有一种方法可以进入数据进入管道.AFAIK(和IIRC)没有关闭其他进程中的读取fd没有问题 - 也就是说,除了文件无缘无故地打开之外.

在退出应用程序之前关闭所有描述符(也就是说,在每个进程中完成读/写操作后关闭管道的另一端),也建议(这是好的做法,而不是它影响太大)

  • 我有一个,编辑你的整个问题,以便明确你真正想要的东西.然后在这里给出所有答案,以便花时间回应. (4认同)