Путаница в выводе fork () - PullRequest
       66

Путаница в выводе fork ()

0 голосов
/ 03 декабря 2011

Я изучал функцию fork () в течение последних нескольких дней и провел несколько экспериментов, чтобы узнать, как она на самом деле работает.При этом я наткнулся на этот интересный фрагмент кода, который мне не удалось понять.Вот код:

int main(int argc, char *argv[])

{
int p,m;
    p = getppid();
    printf("%d\n",p);

if(fork() == 0) {
    p = getppid();
    printf("%d\n",p);
}

if(fork() == 0) {
    p = getppid();
    printf("%d\n",p);
}

if(fork() == 0) {
    p = getppid();
    printf("%d\n",p);
}

if(fork() == 0) {
    p = getppid();
    printf("%d\n",p);
}



return 0;
}

Вывод этого:

$./a.out
6117
6460
1
user@ubuntu:~/forkbomb$ 1
1
1
1
1
1
1
1
1
1
1
1
6473

Было бы очень мило с вашей стороны, если бы вы объяснили мне, почему pid init является1 появляется вывод.Если это поможет, я хотел бы уточнить, что я пытался создать 5 процессов из заданного.Так что вы можете сказать мне правильный способ сделать это тоже?Спасибо

Ответы [ 5 ]

3 голосов
/ 03 декабря 2011

Родитель начинает с печати PID своего родителя.Затем он переходит к разветвлению четырех дочерних элементов (C1..4) и завершает работу.

C1 печатает свой родительский PID, затем переходит к разветвлению трех собственных дочерних элементов.C2 печатает свой родительский PID, затем переходит к форку двух собственных дочерних элементов.C3 печатает свой родительский PID ...

Каждый разветвленный дочерний элемент продолжает работать после блока if, который его создал, поэтому будет создано немало дочерних элементов.

Когда родительский процесс завершается, дочерние процессыпереопределяются в init, который имеет идентификатор процесса 1.Точные выходные данные будут варьироваться от запуска к запуску, в зависимости от того, когда именно / как запланированы дочерние элементы и выход родителей.

Если вы хотите создать только пять процессов, убедитесь, что дочерние элементы завершены, когда они закончат!

if(fork() == 0) {
    p = getppid();
    printf("%d\n",p);
    exit(0);
}

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

2 голосов
/ 03 декабря 2011

Если родительский процесс дочернего процесса завершается или умирает раньше дочернего процесса, то дочерний процесс называется осиротевшим процессом и принимается init.Это означает, что PPID (родительский PID) ребенка изменится на 1. Это объясняет ваш вывод, так как он приходит от getppid().

Чтобы объяснить количество отображаемых строк, нумеруем строки кода:

 1  int p,m;
 2      p = getppid();
 3      printf("%d\n",p);
 4  
 5  if(fork() == 0) {
 6      p = getppid();
 7      printf("%d\n",p);
 8  }
 9  
10  if(fork() == 0) {
11      p = getppid();
12      printf("%d\n",p);
13  }
14  
15  if(fork() == 0) {
16      p = getppid();
17      printf("%d\n",p);
18  }
19  
20  if(fork() == 0) {
21      p = getppid();
22      printf("%d\n",p);
23  }

Теперь давайте посчитаем все процессы, которые выполняли каждый printf().printf() в строке 3, очевидно, был выполнен только исходным родительским процессом.printf() в строке 7 был выполнен только первым потомком исходного родительского процесса, поскольку fork() возвращает 0 в потомке.Теперь строка 9 достигается двумя процессами: исходным родителем и его первым потомком.Оба они fork и оба их потомка (то есть второй потомок исходного родителя и первый потомок первого потомка исходного родителя) выполняют printf() в строке 12. Строка 14 достигается 4 процессами (исходный родитель, его оба потомка и первый потомок первого потомка первоначального родителя).Все они порождают детей в строке 15, и все четверо детей выполняют printf() в строке 17. Целых 8 процессов достигают строки 19. Каждый из них разветвляется, и 8 детей в младшем поколении выполняют финальный printf()в строке 22.

Первый printf() выполняется 1 раз.Секунда printf() выполняется 1 раз.Третий printf() выполняется 2 раза.Четвертый printf() выполняется 4 раза.Пятый printf() выполняется 8 раз.

Это всего 16 и соответствует вашему выводу.Некоторые из отображаемых PPID равны 1, что указывает на то, что данный родитель выполнялся настолько быстро, что ребенок был усыновлен init до того, как он достиг printf().Остальные больше 1, что указывает на то, что родительский процесс данного процесса все еще работал, когда в дочернем элементе был достигнут printf().Весьма вероятно, что многократное выполнение программы приведет к несколько другому выводу.

Таким образом, вы создаете не 4 дочерних процесса, а 15. Это связано с тем, что ваши дети продолжают выполнять с того момента, когдаfork(), который породил их, возвращается.Это означает, что некоторые из fork() будут выполняться не только исходным родителем, но и его потомками, создавая каскад новых процессов.Если вы хотите создать только 4 дочерних элементов, вы должны убедиться, что оставшийся разветвление происходит только в родительском элементе.

0 голосов
/ 03 декабря 2011

Эта программа создаст 1 + 2 + 4 + 8 = 15 процессов в четырех частях fork () (16, если мы добавим оригинал). Может быть, вы хотите что-то вроде этого:

if(fork() == 0) {
    p = getppid();
    printf("%d\n",p);
} else
    return 0;

getppid () вернет 1, если его родитель не будет найден. Поскольку мы не знаем, как система будет планировать эти процессы, вы можете видеть, что это может произойти в вашей программе.

0 голосов
/ 03 декабря 2011

Прежде всего, 1 происходят из родительского процесса (ов), который уже завершился.Затем родитель становится процессом системной инициализации, 1.

Если вас также раздражает количество получаемых 1 с: начальный процесс разветвляется на 4 дочерних, первый ребенок на этом разветвлении 3есть два потомка, каждый разветвляется по 2, трое потомков - 1 и четверо, которые больше не разворачиваются.Это составляет 1 + 1 + 4 + 3 + 2 + 1 + 4 = 16 процессов.

0 голосов
/ 03 декабря 2011

Что вы пропустили, так это то, что при форке 2 процесса с одинаковой копией кода продолжаются с того места, где вы разветвились.

Родителю возвращается pid дочернего элемента, а дочернему элементу возвращается 0. Таким образом, вы разветвляете 16 процессов (4 факторных), потому что на каждом разветвлении вы удваиваете количество процессов.

Если вы добавите sleep () в конце, чтобы убедиться, что родительские процессы задерживаются достаточно долго, тогда вы получите фактический родительский pid для child (просто добавьте sleep (2) перед возвратом).

Мой вывод:

> ./x
19291
21686
21686
21687
21688
21687
21687
21688
21689
21691
21690
21689
21695
21686
21686
21694
...