fork() 函数在 if 语句中的行为如何?

How does the fork() function behave in if statements?

这里的 fork() 调用如何工作?我试图使用打印语句来理解它,但我对它感到更加困惑。我知道 !fork() 检查它是否是子进程意味着 fork()==0 & if (fork()) 意味着它是否是父进程。我不明白我们是如何得到这个输出的。如果有人能给出解释,这将消除我对 if 语句中 fork 调用的疑虑。

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

static int x = 0;

int main(int argc, char *argv[])
{
    pid_t p = getpid();
    x++;
    fork();

    if (!fork())
    {

        if (fork())
        {
            x++;

        }
        x++;
    }

    printf("p%d: x = %d\n", getpid() - p, x);
    sleep(60);
    return 0;
}

输出:

p0: x = 1
p1: x = 1
p2: x = 3
p4: x = 2
p3: x = 3
p5: x = 2

关于你的问题,输出是如何实现的?

以下讨论假设fork()总是成功

fork();
// now have both parent and child processes

if (!fork())
// total of 4 processes
// now have a parent and a child process for each of the prior parent and child process 
// but only the two child processes are executing inside this `if` body
{

    if (fork())
    // now have 6 processes
    // now have another parent and child process for each of the prior processes 
    // but only the two new parent processes are executing inside this `if` body
    {
        x++;
    }

您需要更多详细信息吗?

执行第一个 fork(); 调用后,您现在有两个进程 运行。

执行 if (!fork()) 后,您现在有四个进程(因为前两个已分叉)。但是,if 条件的主体只会在其中两个(子进程)中执行。这意味着 x 将在 if 条件的主体内仅在两个过程中递增。

然后,在执行 if (fork()) 之后,这两个子进程将自己分叉,这意味着您现在总共有六个进程。但是 x 仅在两个父进程中递增,在这两个进程中赋予它最终值 3。

别想if中的fork()调用,想什么fork() 确实如此。

fork() 是一个函数,它 通过复制 调用进程(参见man 2 fork)。这意味着当您调用 fork() 并假设调用没有失败,那么你将有两个进程, 原始过程和一个新过程,即原始过程的副本。做什么 "copy" 是什么意思?表示内存和进程恢复的点 工作是一样的(实际上是复制意味着更多,但我尽量保持它 简单)。

现在有 2 个进程,它们都在同一点恢复工作。 但它们在一个关键点上有所不同:fork() 调用的 return 值:

  • parent(又名原始)获取分叉进程的 pid
  • child(又名副本)从分叉进程中获取 0

这是区分 parent 和 child 的唯一方法。所以当你工作时 对于 fork,您应该使用此模式:

pid_t pid = fork();

if (pid < 0)
{
    // ABORT, ERROR
    // no processes created
}

if(pid == 0)
{
    // CHILD PROCESS
} else {
    // PARENT PROCESS

    // at some point, parent needs to wait for the child
    waitpid(pid, NULL, 0);  // see man 2 waitpid for more info on that
}

那么,让我们看一下您的代码:

  • 第一个fork() x 的值是1。两个进程都保持运行。 让我们调用 parent 进程 A 和 child 进程 B.
  • 在第二个 fork() AB 生成新进程,让我们忘记 他们一秒钟。在 A 的情况下,第二个 fork() returns 的 pid 下一个过程(C、child of A)并且由于 ! 表达式的计算结果为 0,因此 inner inner 语句不会为 A 执行,它会跳转到打印 1.
  • printf
  • 这同样适用于 B,因为它是 A.
  • 的副本
  • 现在让我们考虑第二个 fork()
  • 我们知道 A 会生成第二个 child、C。我们知道 A 发生了什么 然后。但是 fork()C 中调用 returns 0,所以 ! 将其评估为 1 并执行内部 if 语句。
  • 现在它再次调用 fork(),这里 C 产生 D 但 C 的 fork() 调用得到 D 的 pid,if 计算结果为真并执行 x++ 之后 再次 x++。所以当它最终打印出 x 的值时,你得到 3。因为我们 说的是CA的grandchild,getpid() - p是2.
  • 等等

我不会继续解开 fork() 调用,但现在你知道怎么做了 fork()乖乖,拿笔和纸继续做。 您会看到打印件中的值匹配。

编辑:

我建议您阅读 fork() 的手册页。打开终端并输入

man 2 fork

它更详细地解释了 fork() 的工作原理以及副本的含义。

您还应该阅读 waitpid 的手册页。你需要调用它,除非 你想要僵尸进程。