进程未按预期顺序执行; fork() 和 waitpid()
Processes not executing in expected order; fork() and waitpid()
我写了一个调用 fork()
两次的程序,生成了三个 children 和一个 parent。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
int child1 = fork();
int child2 = fork();
// Check for error
if (child1 < 0 || child2 < 0) {
fprintf(stderr, "A fork failed :(\n");
exit(1);
}
// Parent Process
if (child1 > 0 && child2 > 0) {
waitpid(child1, NULL, 0);
waitpid(child2, NULL, 0);
printf("I'm the parent\n");
}
// Child B -- CONFUSION AREA --
else if (child1 > 0 && child2 == 0) {
waitpid(child1, NULL, 0); // Not waiting for process to finish
printf("I'm child B\n");
}
// Child A
else if (child1 == 0 && child2 > 0) {
waitpid(child2, NULL, 0);
printf("I'm child A\n");
}
// Child C
else if (child1 == 0 && child2 == 0) {
printf("I'm child C\n");
}
return 0;
}
我正在尝试打印出来
I'm child C
I'm child A
I'm child B
I'm the parent
但相反,程序打印出
I'm child B
I'm child C
I'm child A
I'm the parent
我很困惑为什么 child B 不等待 child1
进程完成?
我画了一个流程树试图理解发生了什么,我的理解是它看起来像:
/*
Parent (15543)
child1 = 15544;
child2 = 15545
/ \
/ \
/ \
A (15544) B (15545)
child1 = 0; child1 = 15544;
child2 = 15546; child2 = 0;
/
/
/
C (15546)
child1 = 0;
child2 = 0;
*/
当子进程 B 调用 waitpid()
时调用失败并且 returns -1 因为父进程已经在等待子进程 A,你不能两次获取子进程。
对于您想要的行为,最好使用进程间信号量来同步您的进程执行。尝试包含 semaphore.h
并查看 sem_init()
.
的文档
当您执行第一个 fork()
时,两个进程(parent 和 child)都会转到第二个 fork()
并生成您在树。这就是您在输出中看到 grandchild 的原因。你以为只有两个fork被执行,所以应该有两个children,但是你没有意识到第二个fork()
实际上是由两个进程执行的:parent 和第一个 fork()
调用的 child。
顺便说一句,内核以任意顺序安排进程,因此您可以预期输出行中的顺序不同。 Child B 不能 waitpid()
因为它没有启动任何 child (它是你树中的 child B,它有 parent 得到的 pid child A,但是 child A 不是它的 child,所以 waitpid()
给你一个错误,你不检查,所以打印完成)你假设这是一个 parent,因为其中一个 child 变量 > 0,但他继承了从其 parent 初始化的那个变量,因为它没有执行 fork()
调用。
我写了一个调用 fork()
两次的程序,生成了三个 children 和一个 parent。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
int child1 = fork();
int child2 = fork();
// Check for error
if (child1 < 0 || child2 < 0) {
fprintf(stderr, "A fork failed :(\n");
exit(1);
}
// Parent Process
if (child1 > 0 && child2 > 0) {
waitpid(child1, NULL, 0);
waitpid(child2, NULL, 0);
printf("I'm the parent\n");
}
// Child B -- CONFUSION AREA --
else if (child1 > 0 && child2 == 0) {
waitpid(child1, NULL, 0); // Not waiting for process to finish
printf("I'm child B\n");
}
// Child A
else if (child1 == 0 && child2 > 0) {
waitpid(child2, NULL, 0);
printf("I'm child A\n");
}
// Child C
else if (child1 == 0 && child2 == 0) {
printf("I'm child C\n");
}
return 0;
}
我正在尝试打印出来
I'm child C
I'm child A
I'm child B
I'm the parent
但相反,程序打印出
I'm child B
I'm child C
I'm child A
I'm the parent
我很困惑为什么 child B 不等待 child1
进程完成?
我画了一个流程树试图理解发生了什么,我的理解是它看起来像:
/*
Parent (15543)
child1 = 15544;
child2 = 15545
/ \
/ \
/ \
A (15544) B (15545)
child1 = 0; child1 = 15544;
child2 = 15546; child2 = 0;
/
/
/
C (15546)
child1 = 0;
child2 = 0;
*/
当子进程 B 调用 waitpid()
时调用失败并且 returns -1 因为父进程已经在等待子进程 A,你不能两次获取子进程。
对于您想要的行为,最好使用进程间信号量来同步您的进程执行。尝试包含 semaphore.h
并查看 sem_init()
.
当您执行第一个 fork()
时,两个进程(parent 和 child)都会转到第二个 fork()
并生成您在树。这就是您在输出中看到 grandchild 的原因。你以为只有两个fork被执行,所以应该有两个children,但是你没有意识到第二个fork()
实际上是由两个进程执行的:parent 和第一个 fork()
调用的 child。
顺便说一句,内核以任意顺序安排进程,因此您可以预期输出行中的顺序不同。 Child B 不能 waitpid()
因为它没有启动任何 child (它是你树中的 child B,它有 parent 得到的 pid child A,但是 child A 不是它的 child,所以 waitpid()
给你一个错误,你不检查,所以打印完成)你假设这是一个 parent,因为其中一个 child 变量 > 0,但他继承了从其 parent 初始化的那个变量,因为它没有执行 fork()
调用。