为什么包括fork()调用会创建更多循环

时间:2019-04-03 06:23:59

标签: perl loops fork

当我在循环中包含fork()函数调用时,循环执行的次数超过了预期的时间。为了简单起见,我仅选择了两次迭代;您可以进行更多测试。

我尝试设置autoflush on,但这似乎不起作用。

use strict;
use warnings;
use IO::Handle;

$|++; #autoflush on
STDOUT->flush();

for my $i (1 .. 2) {
    print "Normal => $i\n";
}
print "\n";

for my $i (1 .. 2) {
    my $pid = fork();
    if(not defined($pid)) {
       die "cannot fork\n";
    } elsif (not $pid) {
       print "Child  => $i\n";
    } else {
       print "Parent => $i\n";
       wait();
    }
}

实际输出

Normal => 1
Normal => 2

Parent => 1
Child  => 1
Parent => 2
Child  => 2
Parent => 2
Child  => 2

预期产量

Normal => 1
Normal => 2

Parent => 1
Child  => 1
Parent => 2
Child  => 2

请帮助我了解这里出了什么问题。

3 个答案:

答案 0 :(得分:3)

您最终致电fork() 三遍 ,总共进行了四个进程。

以下是可能产生您所看到的输出的一种执行序列:

Process 1       Process 2       Process 3       Process 4
$i == 1
fork----------->$i == 1
"Parent 1"
                "Child 1"
$i == 2
fork--------------------------->$i == 2
"Parent 2"
                                "Child 2"
                $i == 2
                fork--------------------------->$i == 2
                "Parent 2"
                                                "Child 2"
 wait
                reaped          
                                zombie          zombie

答案 1 :(得分:3)

Jim Garisson's answer中所述,您最终调用了fork 3次,因此创建了3个附加进程。

这是一个更简单的示例,它可以帮助您了解正在发生的事情:

say "Start";
fork();
say "Middle";
fork();
say "End";

可能的输出之一是:

Start
Middle
Middle
End
End
End
End

最初的过程说“开始”,然后分叉,因此您最终得到两个过程,每个过程说“中间”,然后分叉,每个过程又创建了一个附加过程,因此最终您说了4个过程,说“结束” “。

图形表示可能会有用:

 "Start"
    |
  fork()
    |
    ------------------------------
    |                            |
 "Middle"                     "Middle"
    |                            |
  fork()                       fork()
    |                            |
    ---------------              ---------------
    |             |              |             |
  "End"         "End"          "End"         "End"

答案 2 :(得分:1)

类似的问题和答案可以在https://stackoverflow.com/a/8318556/542995

中找到

因为您的代码将有第一个孩子开始与父代完全相同的迭代。

因此,只是为了简单起见,以防止出现额外的循环。您可能必须exit子级作业,并将wait();置于父级,以在单独的循环中响应已完成的作业。而且,这将达到您的期望。

use strict;
use warnings;

my $n = 2;

for my $i (1 .. $n) {
  my $pid = fork;
  if (not $pid) {
    print "Child: $i\n";
    exit;
  } else {
    print "Parent $i\n";
  }
}

for (1 .. $n) {
   wait();
   print "Job finished\n";
}

输出:

Parent 1
Parent 2
Child: 1
Child: 2
Job finished
Job finished