fork() 在这里做什么?

What is fork() doing here?

所以我想弄清楚这段代码在做什么:

int k = 5;
 if(fork() == fork()) ++k; else --k;
 printf("%d\n", k);

困扰我的是我收到不同的输出:

4
4
4
6
4
4
4
4
4
6
4
4
4
6
4
6
4
4

我添加了一个 PID 检测器,所以我看到了所有进程的 ID:

int main ()
{
   int k = 5;
    if(fork() == fork()) ++k; else --k;
    printf("%d\n", k);
    int pid;
    pid = fork();
    if(pid == 0)
    {
         printf("\n Process id : %d",getpid());
         printf("\n Parrent process id : %d\n" ,getppid());
    }

    return 0;
}

但有时我得到输出:

Process id : 9472
 Parrent process id : 1413

 Process id : 9474
 Parrent process id : 1413

 Process id : 9471
 Parrent process id : 1413

 Process id : 9473
 Parrent process id : 1413

或:

 Process id : 9557
 Parrent process id : 1413

 Process id : 9556
 Parrent process id : 1413

 Process id : 9558
 Parrent process id : 9554

 Process id : 9559
 Parrent process id : 9553

请让我明白这里发生了什么。

我将 children 的原始代码扩展为 wait,这样您一定会获得所有输出并添加更多输出。

你有两个fork所以总共有四个进程。

只有在其中一个过程中,fork() == fork() 才会成为 true。这是当这两个 fork() 中的第一个 returns 被调用到 child 进程时,下一个 fork() 被调用,同时 returns 被调用到 child 进程。

#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>

const char *foo(pid_t a, pid_t b) {
    if (a == b) return "child,child";
    if (a && b) return "parent,parent";
    if (a) return "parent,child";
    return "child,parent";
}

int main() {
    int k = 5;
    pid_t p1, p2;

    if ((p1 = fork()) == (p2 = fork())) {
        ++k;
    } else {
        --k;
    }

    printf("%d %s\tppid=%d  pid=%d\n", k, foo(p1, p2), getppid(), getpid());

    int wstatus;
    if (p1) wait(&wstatus);
    if (p2) wait(&wstatus);
}

示例输出。请注意,顺序可能会更改,因为所有进程同时 运行。

6 child,child   ppid=2  pid=4
4 parent,child  ppid=1  pid=3
4 child,parent  ppid=1  pid=2
4 parent,parent ppid=0  pid=1

这里第一个进程 1 创建了 23 并且在创建 2 的情况下我们得到了 fork() == fork() .

    1
   / \
  2   3
 /
4

The thing that bothers me is that I receive different outputs:

代码无条件呈现fork()s 两次。第一个fork成功后,原来有一个的进程变成了两个。 两个都执行第二个fork,所以,假设所有fork调用都成功,最终有四个进程。

成功时,fork() returns child PID 到原始进程,0 到 child。失败时,它 returns -1 到 parent(没有 child)。如果实际上两个 fork 都成功,那么所有生成的进程的 PID 都会不同,因此 fork() == fork() 将评估为 true 的唯一情况是第一个 child 的 child =],其中两个 fork() 调用都将返回 0。仅在该过程中,k 将递增;在其他进程中它将被递减。

进程不共享内存,因此增量和减量分别反映在各个进程的单独副本中 k。没有对各种进程 运行 的顺序施加控制,原则上它们可以按任何顺序打印它们的 k 值。这涵盖了观察到的三个输出。

但是只打印三个 k 值的情况呢?最可能的解释是第一个 fork() 成功,但在其中一个结果过程中,第二个失败,返回 -1。如果 fork() 失败发生在原始进程中,那么第二个 fork() 的成功实例仍将产生一个进程,其中 fork() == fork() 的计算结果为真。另一方面,如果 fork 失败发生在第一个 child 中,那么 fork() == fork() 中的任何进程都不会评估为真。这将解释两个 three-output 结果。


就 PID 和 PPID 而言,似乎让您感到困惑的一件事是某些进程的 parent 进程终止的影响。初始进程 always 以外的进程的 parent 有一个活动进程。如果进程 P 的原始 parent 在 P 本身终止之前终止,则分配一个不同的 parent; 在 POSIX-conforming 系统上,这将是进程 1

因为您的程序没有做任何事情来确保 parent 进程比它们的 children 更长寿,所以您有时会看到某些原始 parents 在它们的 child仁。这解释了 PPID 模式的变化。但是,关于新 parent 的分配细节,您似乎 运行 在一个不符合 POSIX 的环境(大概是某种容器)中运行您的程序,这在某种程度上掩盖了该问题的根源。