C 程序产生两个进程树而不是一个
C program yields two process trees instead of one
如果我的解释是正确的,从下面的C程序中期望获得一棵进程树,其中从一个父进程生成三个子进程和两个孙进程:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int num;
pid_t t;
for (num = 0; num < 2; num++) {
t = fork();
if (t == 0)
break;
}
t = fork();
printf("I am the process %d and my father is %d\n", getpid(), getppid());
return 0;
}
但是编译执行后,输出结果如下:
I am the process 2133 and my father is 2127
I am the process 2134 and my father is 2133
I am the process 2137 and my father is 778
I am the process 2135 and my father is 778
I am the process 2138 and my father is 778
I am the process 2136 and my father is 778
正如预期的那样,产生了六个进程,但其中四个是由进程 #778 产生的。另一方面,其中只有一个 (#2134) 似乎是由初始过程 (#2133) 产生的。总共生成了两个过程树,而不是一个。
为什么会出现这种行为?是不是说上面提到的四个进程已经被#778进程adopted/reclaimed了?
作为 , you're not waiting for the children to finish in the parent,因此孤立进程在 parents 退出后被 shell 回收。
正确的树结构是:
1
|
2
/ | \
3 4 5
| |
6 7
其中:
- 1 是 shell
- 2是你的主程序;它在循环中产生 3 和 4,在循环后产生 5
- 3 和 4 是由 2 在循环中产生的 children;每个在
break
上存在循环后产生 1 个新的 child(6 和 7)
- 5 在循环之后生成,因此是叶进程
- 6 和 7 是 3 和 4 循环后产生的叶进程
这里是 cleaned-up 代码,可以提供可理解的输出:
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
printf("original process is %d\n", getpid());
for (int num = 0; num < 2; num++) {
if (fork() == 0) { // 0 means child
break;
}
}
fork(); // fork after the loop
printf("I am %d and my parent is %d\n", getpid(), getppid());
while (wait(NULL) > 0) {} // wait for each child process
return 0;
}
示例输出:
original process is 540
I am 540 and my parent is 1
I am 541 and my parent is 540
I am 543 and my parent is 541
I am 542 and my parent is 540
I am 544 and my parent is 540
I am 545 and my parent is 542
我已经执行了你的代码,通过首先打印根进程的 pid,获得了这个输出:
$ pru
start: pid == 6024
I am the process 6025 and my father is 6024
I am the process 6024 and my father is 5524
I am the process 6027 and my father is 6025
I am the process 6028 and my father is 6024
I am the process 6026 and my father is 6024
I am the process 6029 and my father is 6026
我可以重新排序数据以构建树,从进程开始 6024
:
I am the process 6024 and my father is 5524
I am the process 6026 and my father is 6024
I am the process 6029 and my father is 6026
I am the process 6025 and my father is 6024
I am the process 6027 and my father is 6025
I am the process 6028 and my father is 6024
你也可以这样做,通过查看进程 6024 显示完全不同的 parent(在本例中为 5524),它不在进程列表中。
在你的情况下,输出是错误的(或者你修改了它或者发布的代码与产生输出的代码不同)因为过程树不是这里显示的。
- process
6024
执行完整循环,因此,执行三个 fork()
s,创建树更多进程(两个在循环中,一个在循环之后)。
- 其中两个进程(在循环中创建的:
6025
和6026
)break
循环,并在循环外执行fork()
,创建每个进程一个,通过调用循环外的 fork()
。为您提供进程 6027
和 6029
,分别为
你显示的输出,不能排列在这个树结构中,如果我们对行进行排序:
I am the process 2133 and my father is 2127
I am the process 2134 and my father is 2133
I am the process 2137 and my father is 778
I am the process 2135 and my father is 778
I am the process 2138 and my father is 778
I am the process 2136 and my father is 778
因为只有进程 2134
是其他进程的 child... 而不是树。
备注
我在您的问题的评论中看到,出于某种原因,children 已被重新parent 为 shell。在 UNIX 中,没有进程被重新parent 到另一个 parent,除非它是 parent exit()
s *无论如何),在这种情况下,它们被重新parent重新处理为 PID=1(init
或 systemd
进程,这就是 pid 1 的特殊之处)所以你的进程可以重新parented,但绝不会与 PID=1 的进程不同。事实上,你可以通过测试 getppid()
的结果来检查你的 parent 是否已经死亡,如果它是 returns 1
,那么你的 parent 就没有存活不再。
最后,有很多关于此模式和 unix 进程结构的文档,但如果我不得不推荐您阅读它,我应该推荐您参考 POSIX 规范,可从 The Open Group
如果我的解释是正确的,从下面的C程序中期望获得一棵进程树,其中从一个父进程生成三个子进程和两个孙进程:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int num;
pid_t t;
for (num = 0; num < 2; num++) {
t = fork();
if (t == 0)
break;
}
t = fork();
printf("I am the process %d and my father is %d\n", getpid(), getppid());
return 0;
}
但是编译执行后,输出结果如下:
I am the process 2133 and my father is 2127
I am the process 2134 and my father is 2133
I am the process 2137 and my father is 778
I am the process 2135 and my father is 778
I am the process 2138 and my father is 778
I am the process 2136 and my father is 778
正如预期的那样,产生了六个进程,但其中四个是由进程 #778 产生的。另一方面,其中只有一个 (#2134) 似乎是由初始过程 (#2133) 产生的。总共生成了两个过程树,而不是一个。
为什么会出现这种行为?是不是说上面提到的四个进程已经被#778进程adopted/reclaimed了?
作为
正确的树结构是:
1
|
2
/ | \
3 4 5
| |
6 7
其中:
- 1 是 shell
- 2是你的主程序;它在循环中产生 3 和 4,在循环后产生 5
- 3 和 4 是由 2 在循环中产生的 children;每个在
break
上存在循环后产生 1 个新的 child(6 和 7)
- 5 在循环之后生成,因此是叶进程
- 6 和 7 是 3 和 4 循环后产生的叶进程
这里是 cleaned-up 代码,可以提供可理解的输出:
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
printf("original process is %d\n", getpid());
for (int num = 0; num < 2; num++) {
if (fork() == 0) { // 0 means child
break;
}
}
fork(); // fork after the loop
printf("I am %d and my parent is %d\n", getpid(), getppid());
while (wait(NULL) > 0) {} // wait for each child process
return 0;
}
示例输出:
original process is 540
I am 540 and my parent is 1
I am 541 and my parent is 540
I am 543 and my parent is 541
I am 542 and my parent is 540
I am 544 and my parent is 540
I am 545 and my parent is 542
我已经执行了你的代码,通过首先打印根进程的 pid,获得了这个输出:
$ pru
start: pid == 6024
I am the process 6025 and my father is 6024
I am the process 6024 and my father is 5524
I am the process 6027 and my father is 6025
I am the process 6028 and my father is 6024
I am the process 6026 and my father is 6024
I am the process 6029 and my father is 6026
我可以重新排序数据以构建树,从进程开始 6024
:
I am the process 6024 and my father is 5524
I am the process 6026 and my father is 6024
I am the process 6029 and my father is 6026
I am the process 6025 and my father is 6024
I am the process 6027 and my father is 6025
I am the process 6028 and my father is 6024
你也可以这样做,通过查看进程 6024 显示完全不同的 parent(在本例中为 5524),它不在进程列表中。
在你的情况下,输出是错误的(或者你修改了它或者发布的代码与产生输出的代码不同)因为过程树不是这里显示的。
- process
6024
执行完整循环,因此,执行三个fork()
s,创建树更多进程(两个在循环中,一个在循环之后)。 - 其中两个进程(在循环中创建的:
6025
和6026
)break
循环,并在循环外执行fork()
,创建每个进程一个,通过调用循环外的fork()
。为您提供进程6027
和6029
,分别为
你显示的输出,不能排列在这个树结构中,如果我们对行进行排序:
I am the process 2133 and my father is 2127
I am the process 2134 and my father is 2133
I am the process 2137 and my father is 778
I am the process 2135 and my father is 778
I am the process 2138 and my father is 778
I am the process 2136 and my father is 778
因为只有进程 2134
是其他进程的 child... 而不是树。
备注
我在您的问题的评论中看到,出于某种原因,children 已被重新parent 为 shell。在 UNIX 中,没有进程被重新parent 到另一个 parent,除非它是 parent exit()
s *无论如何),在这种情况下,它们被重新parent重新处理为 PID=1(init
或 systemd
进程,这就是 pid 1 的特殊之处)所以你的进程可以重新parented,但绝不会与 PID=1 的进程不同。事实上,你可以通过测试 getppid()
的结果来检查你的 parent 是否已经死亡,如果它是 returns 1
,那么你的 parent 就没有存活不再。
最后,有很多关于此模式和 unix 进程结构的文档,但如果我不得不推荐您阅读它,我应该推荐您参考 POSIX 规范,可从 The Open Group