системный вызов fork () в c - PullRequest
3 голосов
/ 04 января 2012
    #include <stdio.h>
    #include <unistd.h>
    int main()
    {
       fork();
       fork() && fork() || fork();
       fork();

     printf("forked\n");
     return 0;
    }

Это затрудняет понимание того, как рассчитать количество процессов, порожденных после выполнения программы? Помогите мне узнать.

Платформа --UBUNTU 10.04

Ответы [ 5 ]

10 голосов
/ 04 января 2012

Давайте проследим за ветвлением дерева, предполагая, что ни один из вилок не завершится неудачей

fork ();

Теперь у нас есть два процесса, но пока это не такнезависимо от того, кто является потомком и кто является родителем, назовите их p1 и p2

fork ()

Оба этих процесса порождают другого потомка, поэтому у нас есть 4 процесса, для двухдля них (p3, p4) результат равен нулю, для двух других (p1 и p2) он ненулевой

   && fork()

p1 и p2 снова разветвляются, давая p5 и p6 шесть процессовВсего.В p1 и p2 && оценивается как true, поэтому они больше не разветвляются в этой строке.Для p3, p4, p5, p6 значение && оценивается как ложное, поэтому они форкают

              || fork();

здесь, порождая четыре новых процесса, что дает в общей сложности 6 + 4 =10.

fork ();

каждый из 10 процессов снова разветвляется, получается 20.

3 голосов
/ 04 января 2012
fork();

fork системный вызов возвращает целое число: PID процесса в родительском процессе и 0 в дочернем процессе.Если возникает ошибка, процесс не создается и возвращается -1.

|| и && - логические операторы.

Если результат оператора известен после оценкиих левый операнд, они обязаны замыкать (т. е. не оценивать правый операнд):

  • для оператора || его правый операнд не оценивается, если его левый операнд равен! = 0
  • для оператора && его правый операнд не оценивается, если его левый операнд == 0
3 голосов
/ 04 января 2012

Вы не должны использовать fork (), как это. Никогда. И, тем не менее, вам не нужно будет делать это в реальной жизни. Как это использовать:

int main() {
    /* code */
    pid_t pid = fork();
    if (pid < 0) {
        /* error, no child process spawned */
    }
    if (pid > 0) {
        /* we are the parent process, pid is the process ID of the ONE child process spawned */
    }
    /* else, we are the child process, running exactly one command later the fork() was called in the parent. */
    /* some more code */
    return 0;
}
1 голос
/ 04 января 2012

Сохраните файл, скажем, как fork-count.c.Затем скомпилируйте его с gcc fork-count.c -o fork-count.Затем вы можете запустить его и посчитать количество строк вывода с помощью ./fork-count | wc -l.

0 голосов
/ 07 января 2012

Я нашел правильное объяснение этого вопроса на 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;
     }

enter image description here Первые два вызова 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 процессов.

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