Fork()子进程中的变量值

4

我已经提出了一个有关fork()的问题,这里是另一个问题。 给定以下代码:

#include <unistd.h>
#include <stdio.h>

int main()
{
    pid_t pid1, pid2;
    pid1 = fork();
    pid2 = fork();
    if (pid1 != 0 && pid2 != 0)
        printf("A\n");
    if (pid1 != 0 || pid2 != 0)
        printf("B\n");
    exit(0);
}

在第二个fork()之后,pid1pid2的值将是什么?据我所知,第一个fork设置了pid1>0,并且在稍后创建的所有子进程中都相同。然而,pid2会发生什么呢?感谢!
5个回答

6

Fork会将进程复制一份,使得你现在有了两个完全相同的进程。在原始进程中,fork返回新克隆进程的PID。在新的克隆进程中,fork返回0。

Parent process:
pid1 = PID of child 1
pid2 = PID of child 3

Child 1
pid1 = 0
pid2 = PID of child 2

Child 2
pid1 = 0
pid2 = 0

Child 3
pid1 = PID of child 1
pid2 = 0

1
两个几乎相同的拷贝! 请参见https://dev59.com/NXI-5IYBdhLWcg3w0cOG#1653415——不仅仅是返回值不同。 - paxdiablo
3
我认为不会有一个子进程4,而子进程3中的pid1将是子进程1的PID。 - Edward Strange

5

你只需要尝试一下:

#include <unistd.h>
#include <stdio.h>
int main (void) {
    pid_t pid1 = -1, pid2 = -1;
    pid1 = fork();
    pid2 = fork();
    printf ("%5d/%5d: %5d %5d\n", getpid(), getppid(), pid1, pid2);
    sleep (5); // to prevent inheritance by init process on parent death
    return 0;
}

你会看到:

  PID/ PPID   pid1  pid2
 ----------   ----  ----
 2507/ 2386:  2508  2509      first process
 2508/ 2507:     0  2510      first fork from 'first process'
 2509/ 2507:  2508     0      second fork from 'first process'
 2510/ 2508:     0     0      second fork from "first fork from 'first process'"

换句话说:
  • 第一个进程2507的pid1pid2分别设置为它的两个子进程。
  • 第二个进程2508的pid1为0,因为它是在那个fork中创建的子进程,但pid2为2510,因为它是在那个fork中的父进程。
  • 第三个进程2509从第一个进程(它的父进程)继承了pid1,因为它是在那个之后fork的。它的pid2为0,因为它是第二次fork中的子进程。
  • 第四个进程2510从第二个进程(它的父进程)继承了pid1,因为它是在那个之后fork的。它的pid2也为0,因为它是第二次fork中的子进程。

3

我即将为您测试这个,但是让我告诉您我的期望。

                               / pid2=[child3 pid]    { pid1 = child1;pid2 = child3;}
        pid1=[child1 pid] fork()
       /                       \
      /                          pid2=0               { pid1 = child1;pid2 = 0;}
fork()
      \                          pid2=[child2 pid]    { pid1 = 0;     pid2 = child2;}
       \                       /
        pid1=0         - fork()
                               \ 
                                 pid2=0               { pid1 = 0;     pid2 = 0;}

编辑 已经测试过了。代码如下:

#include <stdio.h>
#include <unistd.h>

int main()
{
    pid_t pid1, pid2;
    pid1 = fork();
    pid2 = fork();
    printf("PID %d: pid1=%d, pid2=%d\n",getpid() ,pid1, pid2);
    exit(0);
}

输出:

PID 30805: pid1=30806,pid2=30807
PID 30806: pid1=0,pid2=30808
PID 30807: pid1=30806,pid2=0
PID 30808: pid1=0,pid2=0


1
你忘记了第一个父进程中第二个fork的影响。 - Edward Strange
我认为我没有...每个叶子上方都有PID变量。最顶部(右侧)的叶子有[child1 pid]、[child2 pid]等等。我添加了一张表以澄清。 - Robert
是的,我意识到子进程也进行了fork()。@Martin York:感谢您的格式化...我想您的副本已经过期了 - 我添加了一个表格 - 但这种格式更清晰。 - Robert

2
在第二个fork()后,pid1和pid2的值取决于您要讨论哪个进程。这里有四个进程(包括原始进程),它们之间的关系如下:
A (original process)
` - B (created by first fork in original process)
|   ` - C (created by second fork in B)
` - D (created by second fork in original process)

在A中,pid1 > 0pid2 > 0,因为它在每个fork上创建了新的进程。
在B中,pid1 == 0pid2 > 0,因为它是由第一个fork创建的,并在第二个fork中创建了一个新进程。
在C中,pid1 == 0pid2 == 0,因为它从其父进程(B)继承了pid1的值,并由第二个fork创建。
在D中,pid1 > 0pid2 == 0,因为它从其父进程(A)继承了pid1的值,并由第二个fork创建。
当然,要记住这些只是初始条件。每个进程都有自己的变量副本,因此即使进程从其父进程继承了某个变量的初始值,也可以在fork之后更改该值,而不影响父进程的副本。

1

阅读手册页:http://linux.die.net/man/2/fork

在第一次 fork 中创建的第一个进程的子进程中,pid1 将为 0,在主进程和其第二个子进程中,pid1 将为其他值。 在第一次进程的孙子进程和主进程的第二个 fork 中创建的子进程中,pid2 将为 0。在其他所有地方,pid2 将为其他值。

                                            /-[parent]pid1=?, pid2=?
      /-[parent]pid1=?, pid2=uninit -> fork()
fork()                                      \-[child2 of parent]pid1=?, pid2=0
     \
      \                                               /-[child1 of parent]pid1=0,pid2=?
       \[child1 of parent] pid1=0, pid2=uninit -> fork()
                                                      \-[child of child] pid1=0, pid2=0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接