理解 pipe() 函数
understanding pipe() function
我正在尝试了解 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])
关闭文件描述符有什么好处。其次,我们在子进程中使用 write
并在父进程中使用 read
,但是如果父进程在子进程到达 write
之前达到 read
并尝试从其中没有任何内容的管道中读取怎么办?谢谢!
Daniel Jour 已经以非常简洁易懂的方式为您提供了 99% 的答案:
Closing: Because it's good practice to close what you don't need. For the second question: These are potentially blocking functions. So reading from an empty pipe will just block the reader process until something gets written into the pipe.
我会尽量详细说明。
收盘价:
当一个进程被分叉时,其打开的文件会被复制。
每个进程对其允许打开的文件描述符数量都有限制。如文档中所述:管道的每一侧都是一个 fd
,这意味着管道需要两个文件描述符,在您的示例中,每个进程仅使用 one.
通过关闭您不使用的文件描述符,您将释放供应有限的资源,并且您可能会在未来进一步需要这些资源。
例如,如果您正在编写服务器,那么额外的 fd
意味着您可以处理更多的客户端。
此外,尽管在退出时释放资源是 "optional",但这是一个很好的做法。未正确释放的资源应由 OS...
处理
...但是OS也是我们程序员写的,我们确实会出错。因此,只有认领资源并了解资源的人才会好心释放资源才有意义。
竞争条件(read
在 write
之前):
POSIX 定义了一些行为,使 read
、write
和管道成为线程和进程并发同步的良好选择。您可以在 the Rational section for write 上阅读更多相关信息,但这里有一个简要说明:
默认情况下,管道(和套接字)是在所谓的 "blocking mode" 中创建的。
这意味着应用程序将挂起,直到执行 IO 操作。
另外,IO操作是atomic
,意思是:
您永远不会同时阅读和写作。 read
操作将等到 write
操作完成后再从管道读取(反之亦然)
如果两个线程同时调用read
,每个线程都会得到一个串行(非并行)响应,从管道顺序读取(或套接字)- 这使管道成为并发处理的好工具。
换句话说,当您的应用程序调用时:
read(fd[0], readbuffer, sizeof(readbuffer));
您的应用程序将永远等待一些数据可用并等待read
操作完成(它将等待80次(sizeof(readbuffer)
)字节被读取,或者 EOF 状态在读取过程中发生变化)。
我正在尝试了解 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])
关闭文件描述符有什么好处。其次,我们在子进程中使用 write
并在父进程中使用 read
,但是如果父进程在子进程到达 write
之前达到 read
并尝试从其中没有任何内容的管道中读取怎么办?谢谢!
Daniel Jour 已经以非常简洁易懂的方式为您提供了 99% 的答案:
Closing: Because it's good practice to close what you don't need. For the second question: These are potentially blocking functions. So reading from an empty pipe will just block the reader process until something gets written into the pipe.
我会尽量详细说明。
收盘价:
当一个进程被分叉时,其打开的文件会被复制。
每个进程对其允许打开的文件描述符数量都有限制。如文档中所述:管道的每一侧都是一个 fd
,这意味着管道需要两个文件描述符,在您的示例中,每个进程仅使用 one.
通过关闭您不使用的文件描述符,您将释放供应有限的资源,并且您可能会在未来进一步需要这些资源。
例如,如果您正在编写服务器,那么额外的 fd
意味着您可以处理更多的客户端。
此外,尽管在退出时释放资源是 "optional",但这是一个很好的做法。未正确释放的资源应由 OS...
处理...但是OS也是我们程序员写的,我们确实会出错。因此,只有认领资源并了解资源的人才会好心释放资源才有意义。
竞争条件(read
在 write
之前):
POSIX 定义了一些行为,使 read
、write
和管道成为线程和进程并发同步的良好选择。您可以在 the Rational section for write 上阅读更多相关信息,但这里有一个简要说明:
默认情况下,管道(和套接字)是在所谓的 "blocking mode" 中创建的。 这意味着应用程序将挂起,直到执行 IO 操作。
另外,IO操作是atomic
,意思是:
您永远不会同时阅读和写作。
read
操作将等到write
操作完成后再从管道读取(反之亦然)如果两个线程同时调用
read
,每个线程都会得到一个串行(非并行)响应,从管道顺序读取(或套接字)- 这使管道成为并发处理的好工具。
换句话说,当您的应用程序调用时:
read(fd[0], readbuffer, sizeof(readbuffer));
您的应用程序将永远等待一些数据可用并等待read
操作完成(它将等待80次(sizeof(readbuffer)
)字节被读取,或者 EOF 状态在读取过程中发生变化)。