Визуально, что происходит с fork() в цикле For
я пытался понять fork()
поведение. На этот раз в for-loop
. Соблюдайте следующий код:
#include <stdio.h>
void main()
{
int i;
for (i=0;i<3;i++)
{
fork();
// This printf statement is for debugging purposes
// getppid(): gets the parent process-id
// getpid(): get child process-id
printf("[%d] [%d] i=%dn", getppid(), getpid(), i);
}
printf("[%d] [%d] hin", getppid(), getpid());
}
вот вывод:
[6909][6936] i=0
[6909][6936] i=1
[6936][6938] i=1
[6909][6936] i=2
[6909][6936] hi
[6936][6938] i=2
[6936][6938] hi
[6938][6940] i=2
[6938][6940] hi
[1][6937] i=0
[1][6939] i=2
[1][6939] hi
[1][6937] i=1
[6937][6941] i=1
[1][6937] i=2
[1][6937] hi
[6937][6941] i=2
[6937][6941] hi
[6937][6942] i=2
[6937][6942] hi
[1][6943] i=2
[1][6943] hi
Я очень визуальный человек, и поэтому единственный способ для меня, чтобы действительно понять вещи, диаграмм. Мой инструктор сказал, что будет 8 привет заявления. Я написал и запустил код, и действительно было 8 привет заявления. Но я действительно не понимаю. Поэтому я нарисовал следующую диаграмму:
схема обновлена, чтобы отразить комментарии :)
замечания:
- родительский процесс (основной) должен повторить цикл 3 раза. Тогда printf называется
- на каждой итерации родительского цикла for-loop вилка () называется
- после каждого вызова fork() i увеличивается, и поэтому каждый ребенок начинает цикл for-loop от i до того, как он будет увеличивается
- в конце каждого цикла for-loop печатается "hi"
вот мои вопросы:
- моя схема правильная?
-
почему два экземпляров
i=0
на выходе? - какое значение
i
переносится на каждого ребенка после вызова Fork()? Если же значениеi
переносится, то когда" разветвление " останавливается? - это всегда так, что
2^n - 1
был бы способ подсчитать количество детей, которые раздвоены? Так вот, здесьn=3
, что означает2^3 - 1 = 8 - 1 = 7
дети, что правильно?
3 ответа:
вот как это понимать, начиная с
for
петли.
цикл начинается в родительской,
i == 0
родитель
fork()
s, создание дочернего элемента 1.теперь у вас есть два процесса. Оба печати
i=0
.цикл перезапускается в обоих процессах, теперь
i == 1
.родитель и ребенок 1
fork()
, создание детей 2 и 3.теперь у вас есть четыре процесса. Все четыре печати
i=1
.цикл перезапускается во всех четырех процессов, теперь
i == 2
.родитель и дети от 1 до 3 все
fork()
, создание детей с 4 по 7.теперь у вас есть восемь процессов. Все восемь печати
i=2
.цикл перезапускается во всех восьми процессов, теперь
i == 3
.цикл завершается во всех восьми процессов, как
i < 3
это уже не так.все восемь процессов печати
hi
.все восемь процессов.
так что вы получите
0
напечатано два раза,1
печатал в четыре раза,2
печатается 8 раз, иhi
печатается 8 раз.
- Да, это правильно. (см. ниже)
- нет,
i++
выполнена после вызовfork
, потому что вот такfor
цикл работ.- если все пройдет успешно, то да. Однако, помните, что
fork
может потерпеть неудачу.
небольшое объяснение на втором:
for (i = 0;i < 3; i++) { fork(); }
аналогично:
i = 0; while (i < 3) { fork(); i++; }
так
i
в разветвленных процессах (как родительских, так и дочерних) это значение перед инкрементом. Однако приращение выполняется сразу послеfork()
, поэтому, на мой взгляд, диаграмму можно рассматривать как правильную.
чтобы ответить на ваши вопросы по одному:
моя схема правильная?
да, по сути. Это тоже очень хорошая схема.
то есть, это правильно, если вы трактуете
i=0
etc. метки, относящиеся к итерациям полного цикла. Какая диаграмма не показать, однако, что, после каждогоfork()
, часть итерации текущего цикла послеfork()
вызов также выполняется разветвленным дочерним элементом процесс.почему есть два экземпляра
i=0
на выходе?потому что у вас есть
printf()
послеfork()
, поэтому он выполняется как родительским процессом, так и просто раздвоенным дочерним процессом. Если вы переместитеprintf()
доfork()
, он будет выполняться только родителем (так как дочерний процесс еще не существует).какое значение
i
переносится на каждого ребенка послеfork()
? Если то же значениеi
переносится, то когда" разветвление " останавливается?значение
i
не изменяетсяfork()
, поэтому дочерний процесс видит то же значение, что и его родитель.что нужно помнить о
fork()
это то, что он вызывается один раз, но он возвращается дважды - один раз в Родительском процессе и один раз в недавно клонированном дочернем процессе.для более простого примера рассмотрим следующий код:
printf("This will be printed once.\n"); fork(); printf("This will be printed twice.\n"); fork(); printf("This will be printed four times.\n"); fork(); printf("This will be printed eight times.\n");
ребенок процесс, созданный
fork()
является (почти) точным клоном своего родителя, и поэтому, с его собственной точки зрения, он "помнит", что является его родителем, наследуя все состояние родительского процесса (включая все значения переменных, стек вызовов и выполняемую инструкцию). Единственная непосредственная разница (кроме системных метаданных, таких как идентификатор процесса, возвращаемыйgetpid()
) возвращаемое значениеfork()
, который будет равен нулю в дочернем процессе, но не равен нулю (фактически, идентификатор дочернего процесса) в родитель.это всегда так, что
2^n - 1
был бы способ подсчитать количество детей, которые раздвоены? Так вот, здесьn=3
, что означает2^3 - 1 = 8 - 1 = 7
дети, что правильно?каждый процесс, который выполняет
fork()
превращается в два процесса (за исключением необычных условий об ошибке, гдеfork()
может глючить). Если родитель и ребенок продолжают выполнять один и тот же код (т. е. они не проверяют возвращаемое значениеfork()
, или свои собственные идентификатор процесса и ответвление на разные пути кода на его основе), то каждая последующая вилка будет удваивать количество процессов. Итак, Да, после трех вилок вы получите в общей сложности 23 = 8 процессов.