Оператор с несколькими fork () - PullRequest
2 голосов
/ 15 марта 2012

Дочерний процесс начинает выполняться в той точке, где остановился последний, - после оператора fork. Что если инструкция содержит несколько fork (), например, условное выражение, подобное следующему. Где именно начинается выполнение программы для дочернего процесса. Прежде чем беспокоиться о том, сколько процессов создается, я хотел узнать, пытается ли каждый созданный дочерний процесс оценить оператор fork() && fork() || fork();. Если это так. Как дочерний процесс, который был создан из-за второго оператора fork (), получает информацию из первого fork () для оценки fork() && fork().

main(){
fork() && fork() || fork();
}

Ответы [ 3 ]

7 голосов
/ 15 марта 2012

Дочерний объект, полученный в результате второго fork(), знает о результатах первого fork(), поскольку это точная копия родительского процесса.

Вы можете понять, что происходит, нарисовав для себя маленькое дерево. Начните с первого форка:

         fork()
           /\
          /  \
parent --/    \-- child1

Родитель возвращает PID процесса child1, а child1 возвращает 0. Итак, у нас есть что-то вроде:

PID(child1) && fork() || fork()

в родителе и:

0 && fork() || fork()

у ребенка. Короткое замыкание означает, что середина fork() исходного выражения не выполняется в дочернем элементе, а только в родительском. Итак, что теперь происходит с деревом?

                  fork()
                    /\
                   /  \
         parent --/    \-- child1
         fork()
           /\
          /  \
parent --/    \-- child2

parent является исходным процессом и получает PID child2. child2, как и child1, получает 0. Как выглядят наши выражения сейчас?

parent:  PID(child1) && PID(child2) || fork() = 1 || fork()
child:   0 || fork()
child2:  PID(child1) && 0 || fork() = 0 || fork()

Теперь, снова с помощью короткого замыкания, parent завершено и не выполняет последнее fork(). Однако child и child2 должны. Это оставляет нас со следующим деревом:

                     fork()
                       /\
                      /  \
            parent --/    \-- child1
            fork()            fork()
              /\                /\
             /  \              /  \
            /    \   child1 --/    \-- child1-1
           /      \
          /        \
parent --/          \-- child2
                        fork()
                          /\
                         /  \
               child2 --/    \-- child2-1

И это все. child1 и child2 каждый получает PID своих соответствующих дочерних элементов, а child1-1 и child2-1 каждый возвращает 0. 0. Подставляя эти значения в, окончательные выражения будут:

parent:   1
child1:   0 || PID(child1-1) = 1
child2:   0 || PID(child2-1) = 1
child1-1: 0 || 0 = 0
child2-1: 0 || 0 = 0

И это все - они все уходят.

1 голос
/ 15 марта 2012
fork() && fork() 

эквивалентно написанию:

pid_t x = fork();
if ( x > 0 )
{
    fork();
}

То есть родительский процесс будет разветвляться дважды, поскольку оба условия выполняются; ни один из детей не будет fork(), поскольку оба возвращают 0 из разветвления. Тем не менее, fork() || fork () эквивалентно:

pid_t x = fork();
if ( x == 0 )
{
    fork();
}

Итак, родительский процесс будет fork() один раз, а его дочерний процесс будет fork() один раз.

Если вы говорите asm, попробуйте выложить вывод из этих двух выражений:

movl    %edi, -4(%rbp)
    movq    %rsi, -16(%rbp)
    call    fork
    testl   %eax, %eax
    je  .L3         // jump if eax is zero
    call    fork
    testl   %eax, %eax
    nop
.L3:
    call    fork
    testl   %eax, %eax
    jne .L7         // jump if eax is non-zero.
    call    fork
    testl   %eax, %eax

Обратите внимание, что call fork - это точка, в которой ваш процесс теряет контроль, а затем восстанавливает его с eax, установленным на возвращаемое значение. Этот вопрос поможет понять testl.

Вы должны быть в состоянии понять, что произойдет в вашем комбинированном примере, используя приоритет оператора правила.

1 голос
/ 15 марта 2012

Я не уверен, что может сбить с толку. Когда вызывается функция fork, она создает второй процесс, который является дубликатом существующего процесса. Оба процесса продолжаются именно с того места, где они остановились. Ребенок знает, как продолжать оценивать то же самое, что и родитель, потому что он обладает именно той информацией, которая ему нужна, именно в том месте, в котором он нуждается, потому что он является клоном.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...