Визуально, что происходит с 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=0etc. метки, относящиеся к итерациям полного цикла. Какая диаграмма не показать, однако, что, после каждого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 процессов.