2012-01-04 2 views
2
#include <stdio.h> 
    #include <unistd.h> 
    int main() 
    { 
     fork(); 
     fork() && fork() || fork(); 
     fork(); 

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

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

Платформа --UBUNTU 10,04

+5

Почему бы не начать, скомпилировав и запустив его, и посмотреть, сколько у вас «разветвленных» сообщений? –

+4

Это домашнее задание? Ни один здравомыслящий человек не напишет 'fork() && fork() || вилка() '. Вы можете разделить эту строку и добавить больше отладочного вывода. – ThiefMaster

+1

Я собрал его много раз, каждый раз, когда он получает другой ответ ... см. Здесь http://ideone.com/CXlkR –

ответ

8

проследим вилочных дерево, предполагая, что ни один из вилок не откажет

fork();

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

вилка()

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

&& fork() 

p1 и p2 fork снова, давая p5 и p6, всего шесть процессов. В p1 и p2 значение && имеет значение true, поэтому в этой строке они не разворачиваются. Для р3, р4, Р5, Р6, то && оценивается как ложное, так что они вилка

   || fork(); 

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

fork();

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

2

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

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; 
} 
+0

Возможно, вы правы, но на самом деле это не отвечает на вопрос. –

+0

Эй, медленнее с этими downvotes! Вы, очевидно, не читали мой ответ. В комментариях есть числа выполненных или не выполненных дочерних процессов. Я хотел ответить на его вопрос. –

1

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

+0

Я собрал много раз, но он дает разные результаты. –

+0

Вы имеете в виду, что вы можете запускать программу несколько раз подряд и получать разные результаты? –

+0

прочитайте выше комментарии plz. –

3
fork(); 

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

|| и && являются логическими операторами.

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

  • для || оператора его правый операнд является не вычисляется, если его левый операнд! = 0
  • для && оператора его правый операнд не вычисляется, если его leftt операнда == 0
0

Я нашел правильное объяснение этого вопроса on Geeks for Geeks:

Система вызова вилка() породит процессы, как листья растущего бинарного дерева , Если мы будем называть fork() два раза, это вызовет 22 = 4 процесса. Все эти 4 процесса образуют листовые дети двоичного дерева. В общем случае, если мы называем безусловный уровень l и fork(), мы будем иметь 2l процессов на уровне (l + 1). Это эквивалентно числу максимальных дочерних узлов в двоичном дереве на уровне (l + 1).

В качестве другого примера предположим, что мы вызываем вызов fork() 3 раза безоговорочно. Мы можем представить порожденный процесс, используя полное двоичное дерево с тремя уровнями. На уровне 3 мы будем иметь 23 = 8 дочерних узлов, что соответствует числу запущенных процессов.

Замечание о логических операторов C/C++:

Логический оператор & & имеет больше приоритет, чем ||, и слева направо ассоциативности. После выполнения левого операнда итоговый результат будет оценен, а выполнение правильного операнда зависит от результата левого операнда, а также от типа операции.

В случае И (& &) после оценки левого операнда правый операнд будет оцениваться только в том случае, если левый операнд оценивается в ненулевое значение. В случае OR (||) после оценки левого операнда правый операнд будет оцениваться только в том случае, если левый операнд будет равен нулю.

Возвращаемое значение вилки():

Людей страницы вилки() приводит следующий отрывок о возвращаемом значении,

«В случае успеха, PID дочернего процесса возвращаются в родителе, и 0 возвращается в дочернем элементе. При ошибке -1 возвращается родительскому, никакой дочерний процесс не создается, а errno устанавливается соответствующим образом. "

PID - это как дескриптор процесса и представлен как беззнаковый int. Мы можем заключить, что fork() вернет ненулевое значение в родительском и ноль в child. Проанализируем программу. Для простоты обозначений, маркировать каждую вилку(), как показано ниже,

 #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 Первые две вилки() вызовы называются безоговорочно.

На уровне 0 у нас есть только основной процесс. Основной (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, чтобы оценить значение логической операции OR.

На уровне 3 мы имеем m, C1, C2, C3 в качестве запущенных процессов и C4, C5 в качестве детей. Теперь выражение упрощается до ((B & & C) || D), и в этот момент значение (B & & C) очевидно. У родителей это отличное от нуля, а у детей - ноль. Следовательно, родители знают об итогах общего В & & 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 процессов.

Смежные вопросы