我正在尝试了解pipe()
函数的工作原理,我有以下程序示例
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);
}
我的第一个问题是,在子进程和父进程中使用close(fd[0])
和close(fd[1])
关闭文件描述符可以获得什么好处。其次,我们在child中使用write
,在父级中使用read
,但是如果父进程在子进入read
之前到达write
并尝试从没有任何内容的管道中读取,该怎么办? ?谢谢!
答案 0 :(得分:1)
Daniel Jour已经以非常简洁易懂的方式给出了99%的答案:
结束:因为关闭你不需要的东西是一种很好的做法。对于第二个问题:这些是潜在的阻塞功能。因此,从空管中读取将阻止读取器进程,直到将某些内容写入管道。
我会尝试详细说明。
<强>合强>:
分叉进程时,其打开的文件会重复。
每个进程都限制了允许打开的文件描述符的数量。如文档中所述:管道的每一侧都是一个fd
,这意味着管道需要两个文件描述符,在您的示例中,每个流程仅使用一个。
通过关闭您不会使用的文件描述符,您可以释放供应有限且未来可能需要的资源。
例如,如果您正在编写服务器,那么额外的fd
意味着您可以再处理一个客户端。
此外,虽然在退出时释放资源是&#34;可选&#34;,但这是一种很好的做法。未正确发布的资源应由操作系统处理......
...但操作系统也是由程序员编写的,我们确实犯了错误。所以只有声称拥有资源并了解它的人才能释放资源才有意义。
竞争条件(read
之前write
):
POSIX定义了一些使read
,write
和管道成为线程和进程并发同步的良好选择的行为。您可以在the Rational section for write上详细了解相关信息,但这是一个快速的概述:
默认情况下,管道(和套接字)是在所谓的&#34;阻塞模式&#34;中创建的。 这意味着应用程序将挂起,直到执行IO操作。
此外,IO操作是atomic
,意思是:
你永远不会同时阅读和写作。 read
操作将等到write
操作完成后再从管道读取(反之亦然)
如果两个线程同时调用read
,每个线程将获得串行(非并行)响应,从管道(或套接字)顺序读取 - 这使得管道很好的并发处理工具。
换句话说,当您的应用程序调用时:
read(fd[0], readbuffer, sizeof(readbuffer));
您的应用程序将等待永久以使某些数据可用并完成read
操作(将读取80(sizeof(readbuffer)
)个字节,或者如果在阅读期间EOF状态发生了变化。