从父进程读写子进程
Reading writes of child process from parent process
在下面的代码中,我分叉了 5 次以创建 5 个子进程,每个子进程接收
来自父进程的字符串,子进程将 child-i
写回父进程
其中 i
是子进程for循环中的循环计数器。当我 运行 这个程序时 我
只看到child-0
然后程序就挂了。
int main(int argc, char *argv[])
{
int num_processes = 5;
int pipefd[2 * num_processes][2];
pid_t cpid;
char buf;
if (argc != 2)
{
fprintf(stderr, "Usage: %s <string>\n", argv[0]);
exit(EXIT_FAILURE);
}
for (int i = 0; i < 2 * num_processes; i++)
{
if (pipe(pipefd[i]) == -1)
{
perror("pipe");
exit(EXIT_FAILURE);
}
}
for (int i = 0; i < num_processes; i++)
{
cpid = fork();
if (cpid == -1)
{
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0)
{ /* Child reads from pipe */
close(pipefd[i][1]); /* Close unused write end */
while (read(pipefd[i][0], &buf, 1) > 0)
{
}
char buf[12];
snprintf(buf, 12, "child-%d", i);
write(pipefd[num_processes + i][1], buf, strlen(buf));
write(STDOUT_FILENO, "\n", 1);
close(pipefd[i][0]);
close(pipefd[num_processes + i][0]);
break;
}
else
{ /* Parent writes argv[1] to pipe */
/* Close unused read end */
write(pipefd[i][1], argv[1], strlen(argv[1]));
close(pipefd[i][1]); /* Reader will see EOF */
wait(NULL); /* Wait for child */
char buf;
while (read(pipefd[num_processes + i][0], &buf, 1) > 0)
{
write(STDOUT_FILENO, &buf, 1);
}
close(pipefd[num_processes + i][0]);
}
}
_exit(EXIT_SUCCESS);
}
When I run this program I
only see child-0
and then the program hangs.
是的,因为父级会无限期地等待从 pipefd[num_processes + i][0]
读取更多数据。考虑一下:
while (read(pipefd[num_processes + i][0], &buf, 1) > 0)
从您代码的其他部分来看,您似乎明白在写入端关闭之前进程在从管道读取时不会看到 EOF,但也许您没有意识到 all写端的句柄 需要在关闭底层打开的文件描述之前关闭。或者您可能根本没有考虑到父进程拥有它创建的每个管道的每一端的副本。只要 pipefd[num_processes + i][1]
打开,它就永远不会在 pipefd[num_processes + i][0]
上看到 EOF,无论子项做什么。
作为使用管道的最佳实践,所涉及的每个进程都应在不再需要将其保持打开状态时立即关闭每个管道末端。尤其是写端,因为不关闭它们很容易让你陷入更深的麻烦,但让读端打开会产生资源泄漏,这也会伤害你。
在下面的代码中,我分叉了 5 次以创建 5 个子进程,每个子进程接收
来自父进程的字符串,子进程将 child-i
写回父进程
其中 i
是子进程for循环中的循环计数器。当我 运行 这个程序时 我
只看到child-0
然后程序就挂了。
int main(int argc, char *argv[])
{
int num_processes = 5;
int pipefd[2 * num_processes][2];
pid_t cpid;
char buf;
if (argc != 2)
{
fprintf(stderr, "Usage: %s <string>\n", argv[0]);
exit(EXIT_FAILURE);
}
for (int i = 0; i < 2 * num_processes; i++)
{
if (pipe(pipefd[i]) == -1)
{
perror("pipe");
exit(EXIT_FAILURE);
}
}
for (int i = 0; i < num_processes; i++)
{
cpid = fork();
if (cpid == -1)
{
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0)
{ /* Child reads from pipe */
close(pipefd[i][1]); /* Close unused write end */
while (read(pipefd[i][0], &buf, 1) > 0)
{
}
char buf[12];
snprintf(buf, 12, "child-%d", i);
write(pipefd[num_processes + i][1], buf, strlen(buf));
write(STDOUT_FILENO, "\n", 1);
close(pipefd[i][0]);
close(pipefd[num_processes + i][0]);
break;
}
else
{ /* Parent writes argv[1] to pipe */
/* Close unused read end */
write(pipefd[i][1], argv[1], strlen(argv[1]));
close(pipefd[i][1]); /* Reader will see EOF */
wait(NULL); /* Wait for child */
char buf;
while (read(pipefd[num_processes + i][0], &buf, 1) > 0)
{
write(STDOUT_FILENO, &buf, 1);
}
close(pipefd[num_processes + i][0]);
}
}
_exit(EXIT_SUCCESS);
}
When I run this program I only see
child-0
and then the program hangs.
是的,因为父级会无限期地等待从 pipefd[num_processes + i][0]
读取更多数据。考虑一下:
while (read(pipefd[num_processes + i][0], &buf, 1) > 0)
从您代码的其他部分来看,您似乎明白在写入端关闭之前进程在从管道读取时不会看到 EOF,但也许您没有意识到 all写端的句柄 需要在关闭底层打开的文件描述之前关闭。或者您可能根本没有考虑到父进程拥有它创建的每个管道的每一端的副本。只要 pipefd[num_processes + i][1]
打开,它就永远不会在 pipefd[num_processes + i][0]
上看到 EOF,无论子项做什么。
作为使用管道的最佳实践,所涉及的每个进程都应在不再需要将其保持打开状态时立即关闭每个管道末端。尤其是写端,因为不关闭它们很容易让你陷入更深的麻烦,但让读端打开会产生资源泄漏,这也会伤害你。