什么是 (fork() && fork()) ||叉()打印?

What does (fork() && fork()) || fork() print?

我试图理解这段代码到底打印了什么

int main(void) {

    pid_t r = (fork() && fork()) || fork();

    if (r) {
        printf("a");
    } else {
        printf("b");
    }
}

我特别想了解将打印多少个“a”和“b”。 我找到的第一个解决方案是:3个“a”和2个“b” 但我不太确定,顺便说一句,我认为这可能是解释:

第一个fork() returns 0到child进程(p1)和一个non-zero值到parent(p0)所以children returns 0 的 && 运算符和 || 的短路被采用,需要对其进行评估。

此时 p1 将 fork() 一个 child 进程 (p2) 具有相应的 return 值(p1 为 0,p2 为 non-zero)。 在这个操作之后,p1 的变量 r 是一个 non-zero 值,而 p2 的变量是 0。 这意味着程序将打印“a”和“b”。

回到p0,由于&&的左边部分是non-zero值,需要计算右边的值,所以会有另一个fork()会return 一个 non-zero 值到 p0 和 0 到 child 进程 (p3)。 现在我们需要检查 || 运算符发生了什么:

我知道这类问题已经收到回复,但我只是想确保我的推理是有道理的。

我认为你解释的很正确。
这里有一个table可以通过这段代码总结不同的场景:

r 0 1 1 0 1
p1 0 0 p1 p1 p1
p2 NA NA 0 0 p2
p3 0 p3 p3 0 NA

注:p1指第一个childPID,p2指第二个child,p3指第三个child. NA表示对应的fork()不会因为short-circuit求值而被调用

可以看到,if(r)会被求五次,被取三次(r被求为true),两次不会被取( r 被评估为 false)。

我们知道的:

  • 来自 man forkfork() 应 return 0 到 child 进程并且应 return child 进程到 parent 进程。
  • PID 总是 non-zero。
  • ||&&short-circuited
  • &&当左侧非零时不执行右侧。
  • ||左边为零时不执行右边
  • || 当边之一不为零时为真。
  • && 两边均为非零时为真。
  • false 为零,true 为非零。

好的,接下来会发生什么:

 pid_t r = (fork() && fork()) || fork();

让我们将其总结为 table。每个 r = 第一行 fork() 都是粗体 - 这意味着这个 fork() 将被执行。当 child 具有 fork() = 0 时,这意味着它是“生成的” - parent 具有 child 的 PID,然后作为 [=12= 的 return 值].

stage main process child1 child2 child3 child4
r = (fork() && fork()) || fork()
fork()= child1pid 0
r = (child1pid && fork()) || fork() (0 && ignored) || fork()
fork()= child2pid child3pid 0 0
r = (child1pid && child2pid) || ignored (0 && ignored) || childpid3 (child1pid && 0) || fork() (0 && ignored) || 0
fork()= child4pid 0
r = (child1pid && child2pid) || ignored (0 && ignored) || childpid3 (child1pid && 0) || child4pid (0 && ignored) || 0 (child1pid && 0) || 0
r = true || ignored false || childpid3 false || child4pid false || 0 false || 0
r = true true true false false
print a a a b b

3 次 a 和 2 次 b 将被打印。

如果你在程序中下点功夫,你可以自己测试一下:

  1. 检查您系统的最大 pid:
cat /proc/sys/kernel/pid_max

并打印所有 fork return 值

#define PIDMAX (4194304 + 1)   
//4194304 - max pid value for my system

int main(void) {

    pid_t p[3] = {PIDMAX , PIDMAX, PIDMAX};
    bool r = ((p[0] = fork()) && (p[1] = fork())) || (p[2] = fork());

    if (r) {
        printf("a\n");
    } else {
        printf("b\n");
    }
    for(size_t i = 0; i < sizeof(p) / sizeof(p[0]); i ++)
    {
        if(p[i] == PIDMAX )  printf("N/A%s", (i == sizeof(p) / sizeof(p[0]) - 1) ? "\n" : ", ");
        else printf("%ld%s", (long)p[i], (i == sizeof(p) / sizeof(p[0]) - 1) ? "\n" : ", ");
    }
}

我系统上的输出:

a
5609, 5610, N/A
a
0, N/A, 5611
a
5609, 0, 5612
b
5609, 0, 0
b
0, N/A, 0

a
5733, 5734, N/A
b
0, N/A, 0
a
0, N/A, 5736
a
5733, 0, 5735
b
5733, 0, 0

取决于 运行