【问题标题】:Statement with multiple fork() s具有多个 fork() 的语句
【发布时间】:2012-03-14 22:55:01
【问题描述】:

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

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

【问题讨论】:

  • 那句台词给我留下了情感上的伤痕
  • 为什么这些可笑的分叉问题不断出现?
  • +1 @Oli。我认为它们是可怕的家庭作业问题。
  • 我敢打赌他们甚至来自同一个老师

标签: c fork


【解决方案1】:

第二个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

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 就因第二次 fork() 调用而创建的子项而言,fork() && 不会退出。那么fork() && fork() || fork()这个表达式怎么对那个孩子有意义。
    • 它对父母的意义相同。该过程在 fork 调用中重复。然后每个过程继续,但处理不同的返回值。
    【解决方案3】:
    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 规则计算出在您的组合示例中会发生什么。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-26
      • 1970-01-01
      • 2020-06-19
      相关资源
      最近更新 更多