Я нашел правильное объяснение этого вопроса на Geeks for Geeks :
Процессы вызова системного вызова fork () представляют собой листья растущего двоичного дерева.Если мы вызовем fork () дважды, он вызовет 22 = 4 процесса.Все эти 4 процесса образуют листовые потомки двоичного дерева.В общем, если мы уровень l, и fork () вызывается безоговорочно, у нас будет 2l процессов на уровне (l + 1).Это эквивалентно числу максимальных дочерних узлов в двоичном дереве на уровне (l + 1).
В качестве другого примера предположим, что мы вызывали вызов fork () 3 раза безоговорочно.Мы можем представить порожденный процесс, используя полное двоичное дерево с 3 уровнями.На уровне 3 у нас будет 23 = 8 дочерних узлов, что соответствует числу запущенных процессов.
Примечание по логическим операторам C / C ++:
Логический оператор && имеет больший приоритет, чем|| и слева направо ассоциативность.После выполнения левого операнда будет оцениваться окончательный результат, и выполнение правого операнда зависит от результата левого операнда, а также от типа операции.
В случае AND (&&), после вычисления левого операнда, справаОперанд будет оцениваться, только если левый операнд оценивается как ненулевой.В случае ИЛИ (||), после вычисления левого операнда, правый операнд будет оцениваться, только если левый операнд оценивается в ноль.
Возвращаемое значение fork ():
Страницы руководстваof fork () ссылается на следующую выдержку для возвращаемого значения:
«В случае успеха PID дочернего процесса возвращается в родительском, а 0 - в дочернем.В случае ошибки -1 возвращается в родительский, дочерний процесс не создается, и errno устанавливается соответствующим образом. ”
PID похож на дескриптор процесса и представлен как unsigned int.Мы можем заключить, что fork () вернет ненулевое значение в parent и ноль в child.Давайте проанализируем программу.Для простоты обозначения пометьте каждый fork (), как показано ниже,
#include <stdio.h>
int main()
{
fork(); /* A */
( fork() /* B */ &&
fork() /* C */ ) || /* B and C are grouped according to precedence */
fork(); /* D */
fork(); /* E */
printf("forked\n");
return 0;
}
Первые два вызова fork () вызываются безоговорочно.
На уровне 0 у нас есть только mainпроцесс.Основной (m на диаграмме) создаст дочерний C1, и оба продолжат выполнение.Дочерние элементы пронумерованы в порядке возрастания их создания.
На уровне 1 у нас запущены m и C1, и мы готовы выполнить fork () - B. (Обратите внимание, что B, C и D называются операндамиоператоры && и ||).Начальное выражение B будет выполняться в каждом дочернем и родительском процессе, выполняющемся на этом уровне.
На уровне 2 из-за fork () - B, выполняемого m и C1, мы имеем m и C1 в качестве родителей и,C2 и C3 как дочерние элементы.
Возвращаемое значение fork () - B ненулевое в родительском и ноль в дочернем.Поскольку первым оператором является &&, из-за нулевого возвращаемого значения дочерние элементы C2 и C3 не будут выполнять следующее выражение (fork () - C).Родительские процессы m и C1 продолжат с fork () - C. Дочерние C2 и C3 будут непосредственно выполнять fork () - D, чтобы оценить значение логической операции ИЛИ.
На уровне 3 у нас есть m,C1, C2, C3 как запущенные процессы и C4, C5 как дочерние.Теперь выражение упрощено до ((B && C) || D), и в этот момент значение (B && C) очевидно.У родителей это не ноль, а у детей это ноль.Следовательно, родители знают о результатах общего B && C ||D, пропустит выполнение fork () - D. Так как в дочерних элементах (B && C), оцененных в ноль, они будут выполнять fork () - D. Следует отметить, что дочерние элементы C2 и C3, созданные на уровне 2, также будутзапустите fork () - D, как упомянуто выше.
На уровне 4 у нас будут m, C1, C2, C3, C4, C5 в качестве запущенных процессов и C6, C7, C8 и C9 в качестве дочерних процессов.Все эти процессы безоговорочно выполняют fork () - E и порождают одного потомка.
На уровне 5 у нас будет запущено 20 процессов.Программа (на Ubuntu Maverick, GCC 4.4.5) напечатана «разветвленной» 20 раз.Один раз корень родитель (основной) и отдых дети.Всего будет запущено 19 процессов.