Почему включение вызова fork () создает больше циклов - PullRequest
2 голосов
/ 03 апреля 2019

Когда я включаю вызов функции 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 ]

3 голосов
/ 03 апреля 2019

Как упомянуто в ответе Джима Гариссона , вы в итоге вызываете fork три раза, создавая тем самым 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"
3 голосов
/ 03 апреля 2019

В итоге вы вызываете 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 голос
/ 03 апреля 2019

Аналогичный вопрос и ответ можно найти по адресу 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
...