多个fork()的语句

时间:2012-03-14 22:55:01

标签: c fork

子进程在fork语句之后的最后一个停止的确切位置开始执行。如果语句包含多个fork(),如下所示的条件表达式,该怎么办?准确执行子进程的程序执行的位置。在担心创建了多少进程之前,我想知道创建的每个子进程是否都尝试评估fork() && fork() || fork();语句。如果是这样的话。由于第二个fork()语句而创建的子进程如何从第一个fork()获取信息以评估fork() && fork()

main(){
fork() && fork() || fork();
}

3 个答案:

答案 0 :(得分:7)

第二个fork()产生的孩子知道第一个fork()的结果,因为它是父进程的完全副本

你可以通过为自己画一棵小树来解决发生的事情。从第一个分支开始:

         fork()
           /\
          /  \
parent --/    \-- child1

父级获取child1进程的PID,child1返回0.所以我们有类似的东西:

PID(child1) && fork() || fork()
在父母中

,并且:

0 && fork() || fork()

在孩子身上。短路意味着原始表达式的中间fork()不会在子节点中执行,只在父节点中执行。那么现在树上发生了什么?

                  fork()
                    /\
                   /  \
         parent --/    \-- child1
         fork()
           /\
          /  \
parent --/    \-- child2

parent是原始流程,获得child2的PID。 child2,就像child1一样,获得0.现在我们的表达式是什么样的?

parent:  PID(child1) && PID(child2) || fork() = 1 || fork()
child:   0 || fork()
child2:  PID(child1) && 0 || fork() = 0 || fork()

现在,再次通过短路,parent完成,并且不执行最后fork()。但是,childchild2都必须这样做。这让我们得到了以下树:

                     fork()
                       /\
                      /  \
            parent --/    \-- child1
            fork()            fork()
              /\                /\
             /  \              /  \
            /    \   child1 --/    \-- child1-1
           /      \
          /        \
parent --/          \-- child2
                        fork()
                          /\
                         /  \
               child2 --/    \-- child2-1

就是这样。 child1child2分别获得各自子项的PID,child1-1child2-1各自返回0.将这些值替换为最终表达式为:

parent:   1
child1:   0 || PID(child1-1) = 1
child2:   0 || PID(child2-1) = 1
child1-1: 0 || 0 = 0
child2-1: 0 || 0 = 0

就是这样 - 他们都退出了。

答案 1 :(得分:1)

我不确定什么可能令人困惑。调用fork函数时,它会创建第二个进程,该进程与现有进程重复。这两个过程都从他们中断的地方继续。孩子知道如何继续以与父母相同的方式进行评估,因为它恰好在需要的地方准确地提供了所需的信息,因为它是一个克隆。

答案 2 :(得分:1)

fork() && fork() 

相当于写作:

pid_t x = fork();
if ( x > 0 )
{
    fork();
}

也就是说,父进程将分叉两次,因为两个条件都被评估;两个孩子都不会fork(),因为他们都从分叉返回0。但是,fork() || fork ()相当于:

pid_t x = fork();
if ( x == 0 )
{
    fork();
}

因此,父进程将fork()一次,其子进程将fork()一次。

如果你说asm,试着吐出这两个表达式的输出:

movl    %edi, -4(%rbp)
    movq    %rsi, -16(%rbp)
    call    fork
    testl   %eax, %eax
    je  .L3         // jump if eax is zero
    call    fork
    testl   %eax, %eax
    nop
.L3:
    call    fork
    testl   %eax, %eax
    jne .L7         // jump if eax is non-zero.
    call    fork
    testl   %eax, %eax

请注意,call fork是您的流程失去控制权然后将eax设置为返回值重新获得控制权的点。 This question有助于了解testl

您应该能够使用operator precedence规则计算出组合示例中会发生什么。