使用 fork() 的 C 程序的行为
Behavior of a C program using fork()
给定以下代码,我必须检查它的行为,即产生了多少进程。
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char*argv[])
{
int pid, i , j;
pid_t t;
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
printf("I am the process %d and my father is the process %d\n", getpid(), getppid());
while(wait(NULL)>0) {}
return 0;
}
编译执行后输出结果如下:
I am the process 3749 and my father is the process 2254
I am the process 3750 and my father is the process 3749
I am the process 3751 and my father is the process 3749
I am the process 3752 and my father is the process 3749
I am the process 3754 and my father is the process 3749
I am the process 3753 and my father is the process 3750
I am the process 3755 and my father is the process 3750
I am the process 3756 and my father is the process 3752
I am the process 3757 and my father is the process 3752
I am the process 3758 and my father is the process 3756
I am the process 3759 and my father is the process 3756
这意味着相应的树进程如下所示:
2254
|
-- 3749 ----
/ | \ \
3750 3751 3752 3754
/ \ / \
3753 3755 3756 3757
/ \
3758 3759
如果算上初始工序,一共产生了11道工序。
我预计会生成比 11 个更多的进程;无论如何,我能够理解除最远的叶子(3758 和 3759)之外的所有进程的生成。
程序中有两个for循环,一个嵌套在另一个循环中。由于每个循环内有两个 break 语句,我猜一个或两个循环应该在它们自然结束之前的某个时间点结束。
有人可以确认此代码的行为吗?
提前致谢
这些程序更多的是说明你了解分叉是如何工作的,希望你不要在多个嵌套循环中编写分叉程序。
他们跟踪的方式是在纸上模拟机器,但每次模拟货叉时,您都会复制模拟,将 fork()
的 return 代码设置为零, 并将另一个副本的 return 代码复制到另一个进程的 pid.
让我重新格式化您的程序以使其更容易
int pid;
int i;
int j;
pid_t t;
将保存我们的进程的“当前值”。我们还将用“IP ==>”
指示指令指针位置
int pid;
int i;
int j;
pid_t t;
IP ===>
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
下一步(PID 1)
=== PROCESS 1 ====
int pid;
int i; (set to 0)
int j;
pid_t t;
for (i = 0; i < 2; i++) {
IP ===>
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
下一步(PID 1)
=== PROCESS 1 ====
int pid (set to 1 // fake pid, but easy to count)
int i; (set to 0)
int j;
pid_t t;
for (i = 0; i < 2; i++) {
pid = getpid();
IP ===>
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
下一步(流程 1)
=== PROCESS 1 ====
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t;
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
IP ===>
t = fork();
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
下一步(PID 1)
=== PROCESS 1 ====
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 2, parent process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
IP ===>
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
=== PROCESS 2 ===
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
IP ===>
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
下一步(过程 1)
=== PROCESS 1 ====
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 2, parent process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) { // t == 2 in this process, so enter the block
IP ===>
t = fork();
break;
}
}
if (pid != getpid())
break;
}
=== PROCESS 2 ===
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
IP ===>
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
下一步(PID 1)
=== PROCESS 1 ====
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 2, parent process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
IP ===>
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
=== PROCESS 2 ===
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
IP ===>
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
下一步(过程 1)
=== PROCESS 1 ====
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 2, parent process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) {
IP ===>
t = fork();
break;
}
}
if (pid != getpid())
break;
}
=== PROCESS 2 ===
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
IP ===>
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
下一步(过程 1)
=== PROCESS 1 ====
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 3, parent process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) {
t = fork();
IP ===>
break;
}
}
if (pid != getpid())
break;
}
=== PROCESS 2 ===
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
IP ===>
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
=== PROCESS 3 ====
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child of PID 1)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) {
t = fork();
IP ===>
break;
}
}
if (pid != getpid())
break;
}
下一步(过程 1)
=== PROCESS 1 ====
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 3, parent process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) {
t = fork();
break;
}
}
IP ===>
if (pid != getpid())
break;
}
=== PROCESS 2 ===
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
IP ===>
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
=== PROCESS 3 ====
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child of PID 1)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) {
t = fork();
IP ===>
break;
}
}
if (pid != getpid())
break;
}
下一步(过程 1)
=== PROCESS 1 ====
int pid (set to 1)
int pid = 1;
int i; (set to 0)
int j; (set to 1, due to j++)
pid_t t; (set to 3, parent process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) { // t == 2 in this process, so enter the block
t = fork();
break;
}
}
if (pid != getpid()) // pid == 1, getpid == 1. so skip break
break;
IP ===>
}
=== PROCESS 2 ===
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
IP ===>
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
=== PROCESS 3 ====
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child of PID 1)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) { // t == 2 in this process, so enter the block
t = fork();
IP ===>
break;
}
}
if (pid != getpid())
break;
}
下一步(过程 1)
=== PROCESS 1 ====
int pid (set to 1)
int pid = 1;
int i; (set to 1)
int j; (set to 1, due to j++)
pid_t t; (set to 3, parent process)
for (i = 0; i < 2; IP ===> i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) { // t == 2 in this process, so enter the block
t = fork();
break;
}
}
if (pid != getpid()) // pid == 1, getpid == 1. so skip break
break;
}
=== PROCESS 2 ===
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
IP ===>
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
=== PROCESS 3 ====
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child of PID 1)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) { // t == 2 in this process, so enter the block
t = fork();
IP ===>
break;
}
}
if (pid != getpid())
break;
}
下一步(过程 1)
=== PROCESS 1 ====
int pid (set to 1)
int pid = 1;
int i; (set to 1)
int j; (set to 1, due to j++)
pid_t t; (set to 3, parent process)
for (i = 0; IP ===> i < 2; i++) { // 1 is less than 2 so enter loop block
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) { // t == 2 in this process, so enter the block
t = fork();
break;
}
}
if (pid != getpid()) // pid == 1, getpid == 1. so skip break
break;
}
=== PROCESS 2 ===
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
IP ===>
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
=== PROCESS 3 ====
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child of PID 1)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) { // t == 2 in this process, so enter the block
t = fork();
IP ===>
break;
}
}
if (pid != getpid())
break;
}
下一步(过程 1)
=== PROCESS 1 ====
int pid (set to 1)
int pid = 1;
int i; (set to 1)
int j; (set to 1)
pid_t t; (set to 3, parent process)
for (i = 0; i < 2; i++) {
IP ===>
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) { // t == 2 in this process, so enter the block
t = fork();
break;
}
}
if (pid != getpid()) // pid == 1, getpid == 1. so skip break
break;
}
=== PROCESS 2 ===
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
IP ===>
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
=== PROCESS 3 ====
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child of PID 1)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) { // t == 2 in this process, so enter the block
t = fork();
IP ===>
break;
}
}
if (pid != getpid())
break;
}
下一步(过程 1)
=== PROCESS 1 ====
int pid (set to 1, again)
int pid = 1;
int i; (set to 1)
int j; (set to 1)
pid_t t; (set to 3)
for (i = 0; i < 2; i++) {
pid = getpid();
IP ===>
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) { // t == 2 in this process, so enter the block
t = fork();
break;
}
}
if (pid != getpid()) // pid == 1, getpid == 1. so skip break
break;
}
=== PROCESS 2 ===
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
IP ===>
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
=== PROCESS 3 ====
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child of PID 1)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) { // t == 2 in this process, so enter the block
t = fork();
IP ===>
break;
}
}
if (pid != getpid())
break;
}
下一步(过程 1)
=== PROCESS 1 ====
int pid (set to 1)
int pid = 1;
int i; (set to 1)
int j; (set to 0)
pid_t t; (set to 3)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
IP ===>
t = fork();
if (t != 0) { // t == 2 in this process, so enter the block
t = fork();
break;
}
}
if (pid != getpid()) // pid == 1, getpid == 1. so skip break
break;
}
=== PROCESS 2 ===
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
IP ===>
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
=== PROCESS 3 ====
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child of PID 1)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) { // t == 2 in this process, so enter the block
t = fork();
IP ===>
break;
}
}
if (pid != getpid())
break;
}
等等。一旦您使流程 1 脱离循环(并等待其 children 完成),您将对流程 2 执行相同的过程,直到它脱离循环并等待其 children 完成。
这个练习的重点是你是否可以模拟一些令人困惑的过程代码。很明显,由于顶层进程将循环两次,并且永远不会跳出循环,因此您将在其下获得 4 个进程。当您练习单步执行其他过程时,您将开始看到它们实现的模式。
就个人而言,这类问题需要大量的工作,而不是那种让你成为更好的程序员的工作;但是,它会证明你是否理解一个程序是用它的当前状态分叉的(注意 pid 在许多 children 中是错误的,因为它在分叉后没有更新),如果你完全理解, 你可以模拟程序到它的最终完成。
当然,我们使用计算机来自动处理无聊的事情(像这样),所以你可能想像这样想出一个新的日志行:
void printState(int me, int pid, int i, int j, int t) {
printf("PID %d: pid = %d, i = %d, j = %d, t = %d\n");
}
然后是运行
printState(getpid(), pid, i, j, t);
for (i = 0; i < 2; i++) {
printState(getpid(), pid, i, j, t);
pid = getpid();
printState(getpid(), pid, i, j, t);
for (j = 0 ; j < i+2; j++){
printState(getpid(), pid, i, j, t);
t = fork();
printState(getpid(), pid, i, j, t);
if (t != 0) {
printState(getpid(), pid, i, j, t);
t = fork();
printState(getpid(), pid, i, j, t);
break;
}
}
if (pid != getpid())
printState(getpid(), pid, i, j, t);
break;
}
并收集输出,按它们的 self-reported pid 编号(getpid(),而不是 pid 变量)对它们进行排序
这是基于@Edwin Buck(谢谢Edwin!)解释的程序模拟的进程创建过程
1
|
---- 2 -----
/ / \ \
3 4 5 6
/ \ / \
7 8 9 10
/ \
11 12
进程 #1:初始进程的父进程。
流程#2:初始流程。这是唯一满足 pid = getpid() 的进程。
进程 #3:生成于 i = 0,j = 0。
进程 #4:生成于 i = 0,j = 0。
进程 #7:生成于 i = 0,j = 1。
进程 #8:生成于 i = 0,j = 1。
进程 #5:生成于 i = 1,j = 0。
进程 #6:生成于 i = 1,j = 0。
进程 #9:生成于 i = 1,j = 1。
进程 #10:生成于 i = 1,j = 1。
进程 #11:生成于 i = 1,j = 2。
进程 #12:生成于 i = 1,j = 2。
给定以下代码,我必须检查它的行为,即产生了多少进程。
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char*argv[])
{
int pid, i , j;
pid_t t;
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
printf("I am the process %d and my father is the process %d\n", getpid(), getppid());
while(wait(NULL)>0) {}
return 0;
}
编译执行后输出结果如下:
I am the process 3749 and my father is the process 2254
I am the process 3750 and my father is the process 3749
I am the process 3751 and my father is the process 3749
I am the process 3752 and my father is the process 3749
I am the process 3754 and my father is the process 3749
I am the process 3753 and my father is the process 3750
I am the process 3755 and my father is the process 3750
I am the process 3756 and my father is the process 3752
I am the process 3757 and my father is the process 3752
I am the process 3758 and my father is the process 3756
I am the process 3759 and my father is the process 3756
这意味着相应的树进程如下所示:
2254
|
-- 3749 ----
/ | \ \
3750 3751 3752 3754
/ \ / \
3753 3755 3756 3757
/ \
3758 3759
如果算上初始工序,一共产生了11道工序。
我预计会生成比 11 个更多的进程;无论如何,我能够理解除最远的叶子(3758 和 3759)之外的所有进程的生成。
程序中有两个for循环,一个嵌套在另一个循环中。由于每个循环内有两个 break 语句,我猜一个或两个循环应该在它们自然结束之前的某个时间点结束。
有人可以确认此代码的行为吗?
提前致谢
这些程序更多的是说明你了解分叉是如何工作的,希望你不要在多个嵌套循环中编写分叉程序。
他们跟踪的方式是在纸上模拟机器,但每次模拟货叉时,您都会复制模拟,将 fork()
的 return 代码设置为零, 并将另一个副本的 return 代码复制到另一个进程的 pid.
让我重新格式化您的程序以使其更容易
int pid;
int i;
int j;
pid_t t;
将保存我们的进程的“当前值”。我们还将用“IP ==>”
指示指令指针位置 int pid;
int i;
int j;
pid_t t;
IP ===>
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
下一步(PID 1)
=== PROCESS 1 ====
int pid;
int i; (set to 0)
int j;
pid_t t;
for (i = 0; i < 2; i++) {
IP ===>
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
下一步(PID 1)
=== PROCESS 1 ====
int pid (set to 1 // fake pid, but easy to count)
int i; (set to 0)
int j;
pid_t t;
for (i = 0; i < 2; i++) {
pid = getpid();
IP ===>
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
下一步(流程 1)
=== PROCESS 1 ====
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t;
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
IP ===>
t = fork();
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
下一步(PID 1)
=== PROCESS 1 ====
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 2, parent process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
IP ===>
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
=== PROCESS 2 ===
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
IP ===>
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
下一步(过程 1)
=== PROCESS 1 ====
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 2, parent process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) { // t == 2 in this process, so enter the block
IP ===>
t = fork();
break;
}
}
if (pid != getpid())
break;
}
=== PROCESS 2 ===
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
IP ===>
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
下一步(PID 1)
=== PROCESS 1 ====
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 2, parent process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
IP ===>
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
=== PROCESS 2 ===
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
IP ===>
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
下一步(过程 1)
=== PROCESS 1 ====
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 2, parent process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) {
IP ===>
t = fork();
break;
}
}
if (pid != getpid())
break;
}
=== PROCESS 2 ===
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
IP ===>
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
下一步(过程 1)
=== PROCESS 1 ====
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 3, parent process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) {
t = fork();
IP ===>
break;
}
}
if (pid != getpid())
break;
}
=== PROCESS 2 ===
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
IP ===>
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
=== PROCESS 3 ====
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child of PID 1)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) {
t = fork();
IP ===>
break;
}
}
if (pid != getpid())
break;
}
下一步(过程 1)
=== PROCESS 1 ====
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 3, parent process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) {
t = fork();
break;
}
}
IP ===>
if (pid != getpid())
break;
}
=== PROCESS 2 ===
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
IP ===>
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
=== PROCESS 3 ====
int pid (set to 1)
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child of PID 1)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) {
t = fork();
IP ===>
break;
}
}
if (pid != getpid())
break;
}
下一步(过程 1)
=== PROCESS 1 ====
int pid (set to 1)
int pid = 1;
int i; (set to 0)
int j; (set to 1, due to j++)
pid_t t; (set to 3, parent process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) { // t == 2 in this process, so enter the block
t = fork();
break;
}
}
if (pid != getpid()) // pid == 1, getpid == 1. so skip break
break;
IP ===>
}
=== PROCESS 2 ===
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
IP ===>
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
=== PROCESS 3 ====
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child of PID 1)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) { // t == 2 in this process, so enter the block
t = fork();
IP ===>
break;
}
}
if (pid != getpid())
break;
}
下一步(过程 1)
=== PROCESS 1 ====
int pid (set to 1)
int pid = 1;
int i; (set to 1)
int j; (set to 1, due to j++)
pid_t t; (set to 3, parent process)
for (i = 0; i < 2; IP ===> i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) { // t == 2 in this process, so enter the block
t = fork();
break;
}
}
if (pid != getpid()) // pid == 1, getpid == 1. so skip break
break;
}
=== PROCESS 2 ===
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
IP ===>
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
=== PROCESS 3 ====
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child of PID 1)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) { // t == 2 in this process, so enter the block
t = fork();
IP ===>
break;
}
}
if (pid != getpid())
break;
}
下一步(过程 1)
=== PROCESS 1 ====
int pid (set to 1)
int pid = 1;
int i; (set to 1)
int j; (set to 1, due to j++)
pid_t t; (set to 3, parent process)
for (i = 0; IP ===> i < 2; i++) { // 1 is less than 2 so enter loop block
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) { // t == 2 in this process, so enter the block
t = fork();
break;
}
}
if (pid != getpid()) // pid == 1, getpid == 1. so skip break
break;
}
=== PROCESS 2 ===
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
IP ===>
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
=== PROCESS 3 ====
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child of PID 1)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) { // t == 2 in this process, so enter the block
t = fork();
IP ===>
break;
}
}
if (pid != getpid())
break;
}
下一步(过程 1)
=== PROCESS 1 ====
int pid (set to 1)
int pid = 1;
int i; (set to 1)
int j; (set to 1)
pid_t t; (set to 3, parent process)
for (i = 0; i < 2; i++) {
IP ===>
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) { // t == 2 in this process, so enter the block
t = fork();
break;
}
}
if (pid != getpid()) // pid == 1, getpid == 1. so skip break
break;
}
=== PROCESS 2 ===
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
IP ===>
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
=== PROCESS 3 ====
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child of PID 1)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) { // t == 2 in this process, so enter the block
t = fork();
IP ===>
break;
}
}
if (pid != getpid())
break;
}
下一步(过程 1)
=== PROCESS 1 ====
int pid (set to 1, again)
int pid = 1;
int i; (set to 1)
int j; (set to 1)
pid_t t; (set to 3)
for (i = 0; i < 2; i++) {
pid = getpid();
IP ===>
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) { // t == 2 in this process, so enter the block
t = fork();
break;
}
}
if (pid != getpid()) // pid == 1, getpid == 1. so skip break
break;
}
=== PROCESS 2 ===
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
IP ===>
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
=== PROCESS 3 ====
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child of PID 1)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) { // t == 2 in this process, so enter the block
t = fork();
IP ===>
break;
}
}
if (pid != getpid())
break;
}
下一步(过程 1)
=== PROCESS 1 ====
int pid (set to 1)
int pid = 1;
int i; (set to 1)
int j; (set to 0)
pid_t t; (set to 3)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
IP ===>
t = fork();
if (t != 0) { // t == 2 in this process, so enter the block
t = fork();
break;
}
}
if (pid != getpid()) // pid == 1, getpid == 1. so skip break
break;
}
=== PROCESS 2 ===
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child process)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
IP ===>
if (t != 0) {
t = fork();
break;
}
}
if (pid != getpid())
break;
}
=== PROCESS 3 ====
int i; (set to 0)
int j; (set to 0)
pid_t t; (set to 0, child of PID 1)
for (i = 0; i < 2; i++) {
pid = getpid();
for (j = 0 ; j < i+2; j++){
t = fork();
if (t != 0) { // t == 2 in this process, so enter the block
t = fork();
IP ===>
break;
}
}
if (pid != getpid())
break;
}
等等。一旦您使流程 1 脱离循环(并等待其 children 完成),您将对流程 2 执行相同的过程,直到它脱离循环并等待其 children 完成。
这个练习的重点是你是否可以模拟一些令人困惑的过程代码。很明显,由于顶层进程将循环两次,并且永远不会跳出循环,因此您将在其下获得 4 个进程。当您练习单步执行其他过程时,您将开始看到它们实现的模式。
就个人而言,这类问题需要大量的工作,而不是那种让你成为更好的程序员的工作;但是,它会证明你是否理解一个程序是用它的当前状态分叉的(注意 pid 在许多 children 中是错误的,因为它在分叉后没有更新),如果你完全理解, 你可以模拟程序到它的最终完成。
当然,我们使用计算机来自动处理无聊的事情(像这样),所以你可能想像这样想出一个新的日志行:
void printState(int me, int pid, int i, int j, int t) {
printf("PID %d: pid = %d, i = %d, j = %d, t = %d\n");
}
然后是运行
printState(getpid(), pid, i, j, t);
for (i = 0; i < 2; i++) {
printState(getpid(), pid, i, j, t);
pid = getpid();
printState(getpid(), pid, i, j, t);
for (j = 0 ; j < i+2; j++){
printState(getpid(), pid, i, j, t);
t = fork();
printState(getpid(), pid, i, j, t);
if (t != 0) {
printState(getpid(), pid, i, j, t);
t = fork();
printState(getpid(), pid, i, j, t);
break;
}
}
if (pid != getpid())
printState(getpid(), pid, i, j, t);
break;
}
并收集输出,按它们的 self-reported pid 编号(getpid(),而不是 pid 变量)对它们进行排序
这是基于@Edwin Buck(谢谢Edwin!)解释的程序模拟的进程创建过程
1
|
---- 2 -----
/ / \ \
3 4 5 6
/ \ / \
7 8 9 10
/ \
11 12
进程 #1:初始进程的父进程。
流程#2:初始流程。这是唯一满足 pid = getpid() 的进程。
进程 #3:生成于 i = 0,j = 0。
进程 #4:生成于 i = 0,j = 0。
进程 #7:生成于 i = 0,j = 1。
进程 #8:生成于 i = 0,j = 1。
进程 #5:生成于 i = 1,j = 0。
进程 #6:生成于 i = 1,j = 0。
进程 #9:生成于 i = 1,j = 1。
进程 #10:生成于 i = 1,j = 1。
进程 #11:生成于 i = 1,j = 2。
进程 #12:生成于 i = 1,j = 2。