当父级调用 waitpid() 时,分叉进程不会退出
forked process doesn't exit when parent invoke waitpid()
在这个程序中,2 个子进程被 fork,然后一个通过 pipe
向另一个发送字符串。通信完成后,父进程卡在等待从管道读取的子进程退出 (waitpid(read_child, NULL, 0);
)。它在没有任何 waitpid
(两个子进程都退出)或只是等待 write_child
的情况下工作正常。这是为什么?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
int pipe_fd[2];
if (pipe(pipe_fd) == -1)
{
// fail to build pipe
perror("pipe");
exit(EXIT_FAILURE);
}
int read_child = fork();
if (read_child == 0)
{
sleep(0.5);
close(pipe_fd[1]);
printf("child %d read from pipe:\n", (int)getpid());
char buffer;
while (read(pipe_fd[0], &buffer, 1) > 0)
{
write(STDOUT_FILENO, &buffer, 1);
}
write(STDOUT_FILENO, "\n", 1);
close(pipe_fd[0]);
printf("read child exits\n");
exit(0);
}
int write_child = fork();
if (write_child == 0)
{
sleep(0.5);
close(pipe_fd[0]);
printf("child %d writes to pipe\n", (int)getpid());
char message[100];
sprintf(message, "greeting from brother %d", (int)getpid());
write(pipe_fd[1], message, strlen(message));
close(pipe_fd[1]);
printf("write child exits\n");
exit(0);
}
waitpid(read_child, NULL, 0);
// waitpid(write_child, NULL, 0);
return 0;
}
TL;DR
- 在 parent 进程的
waitpid(read_child, NULL, 0);
之前添加 close(pipe_fd[1]);
将解决问题。
这里的问题是,parent 进程还持有对两个管道 fds 的引用。
read
阻塞直到一些数据可用,或者当 fd
标识的管道关闭并且 read
returns 立即为 0 字节时。
最初,写入管道 fd 的引用计数为 2,来自写入器 child 和 parent。 parent阻塞等待writer,然后writer退出,refcount减1。随着writer退出,parent阻塞等待returns,[=34= 】 也退出。 Refcount 减少到 0,所以管道的写端被关闭,所以 reader 用 0 字节阻塞 read
returns,然后 reader 退出。
然而,如果 parent 等待 reader 而没有首先释放其对管道 fd 写入端的引用,即使写入器已经退出,管道也不会关闭,因为来自 parent 的最终参考。这意味着,reader child 的 read
将永远阻塞...
在这个程序中,2 个子进程被 fork,然后一个通过 pipe
向另一个发送字符串。通信完成后,父进程卡在等待从管道读取的子进程退出 (waitpid(read_child, NULL, 0);
)。它在没有任何 waitpid
(两个子进程都退出)或只是等待 write_child
的情况下工作正常。这是为什么?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
int pipe_fd[2];
if (pipe(pipe_fd) == -1)
{
// fail to build pipe
perror("pipe");
exit(EXIT_FAILURE);
}
int read_child = fork();
if (read_child == 0)
{
sleep(0.5);
close(pipe_fd[1]);
printf("child %d read from pipe:\n", (int)getpid());
char buffer;
while (read(pipe_fd[0], &buffer, 1) > 0)
{
write(STDOUT_FILENO, &buffer, 1);
}
write(STDOUT_FILENO, "\n", 1);
close(pipe_fd[0]);
printf("read child exits\n");
exit(0);
}
int write_child = fork();
if (write_child == 0)
{
sleep(0.5);
close(pipe_fd[0]);
printf("child %d writes to pipe\n", (int)getpid());
char message[100];
sprintf(message, "greeting from brother %d", (int)getpid());
write(pipe_fd[1], message, strlen(message));
close(pipe_fd[1]);
printf("write child exits\n");
exit(0);
}
waitpid(read_child, NULL, 0);
// waitpid(write_child, NULL, 0);
return 0;
}
TL;DR
- 在 parent 进程的
waitpid(read_child, NULL, 0);
之前添加close(pipe_fd[1]);
将解决问题。
这里的问题是,parent 进程还持有对两个管道 fds 的引用。
read
阻塞直到一些数据可用,或者当 fd
标识的管道关闭并且 read
returns 立即为 0 字节时。
最初,写入管道 fd 的引用计数为 2,来自写入器 child 和 parent。 parent阻塞等待writer,然后writer退出,refcount减1。随着writer退出,parent阻塞等待returns,[=34= 】 也退出。 Refcount 减少到 0,所以管道的写端被关闭,所以 reader 用 0 字节阻塞 read
returns,然后 reader 退出。
然而,如果 parent 等待 reader 而没有首先释放其对管道 fd 写入端的引用,即使写入器已经退出,管道也不会关闭,因为来自 parent 的最终参考。这意味着,reader child 的 read
将永远阻塞...