2016-10-19 3 views
2

Я следующий код, который создает определенное количество дочерних потоков с использованием fork():вилка() Детские цепи

#include <pthread.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <sys/types.h> 
#include <unistd.h> 
#include <sys/wait.h> 

#define NUM_THREADS  4 

int main() 
{ 
     int i; 
     pid_t pid; 
     for(i = 0; i < NUM_THREADS; i++){ //Do this equal to the number of threads 
      pid = fork();//Use this to avoid multiple forking 

      if(pid == 0){ //If it's a child process 
        printf("Hello World! Greetings from PID: %ld! :D\n", (long)getpid()); //getpid returns the pid of the process 
        exit(0); //Exit the process 
      }else if(pid == -1){ 
        printf("Oh no! Could not fork! :(Exiting!\n"); 
        return 0; 
      } 
    } 
    int status; 
    for(i = 0; i < NUM_THREADS; i++){ 
      wait(&status);//wait until all the children processes have finished. 
    } 
    printf("All done! I am the parent process! My PID is: %ld if you were curious! \n", (long)getpid()); 

    return 0; 

}

Это был предоставлен нам в качестве примера. Его выход похож:

Hello World! Привет от PID: 118358! : D
Hello World! Привет от PID: 118359! : D
Hello World! Привет от PID: 118360! : D
Hello World! Привет от PID: 118362! : D

Что бы я хотел сделать, вместо того, чтобы иметь один родительский процесс с большим количеством детей, состоит в том, чтобы родительский элемент создавал дочерний процесс, который создает дочерний процесс и т. Д. Для определенного числа потоки. Как я могу это сделать?

+0

Вы пытались закодировать это самостоятельно? С чем вы столкнулись? – davmac

ответ

1

Во-первых, термин «нить», который вы использовали, не подходит в этой ситуации. Вилка означает «создание процесса», а не «потоки».

Вы можете использовать рекурсивное решение, но вы должны помнить, что каждый процесс, создающий процесс, должен ждать статуса возврата, чтобы избежать процесса Zombie. Без использования какой-либо общей переменной между процессом вы можете использовать один счетчик переменных, который увеличивается при каждом форсировании. Но как только переменная счетчика достигла максимального значения, «самый молодой» процесс, я имею в виду, что последний созданный процесс должен выйти, и один за другим будет завершен другой процесс.

Вот простой код, который работает отлично:

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 

#define NUM_PROCESS 5 

int counter = 0; 

void child_func() 
{ 
    pid_t pid; 

    if (counter < NUM_PROCESS) { 

     counter++; 

     pid = fork(); 

     if (pid < 0) { 

      printf("fork failed counter = %d\n", counter); 

     } 
     else if (pid == 0) { 

      printf("Hello world ! Greetings from pid %ld\n", (long)getpid()); 

      if (counter == NUM_PROCESS) { 
       exit(0); 
      } 
      else { 
       child_func(); 
      } 
     } 
     else { 

      long var = pid; 

      wait(&pid); 

      printf("My pid is %ld and i am the parent of %ld child, i exit\n", (long)getpid(), var); 

      exit(0); 
     } 
    } 
} 

int main(void) 
{ 

    pid_t pid; 

    pid = fork(); 

    if (pid < 0) { 

     printf("Fork failed %d\n", counter); 

     return -1; 
    } 

    if (pid == 0) { 

     child_func(); 
    } 
    else { 

     wait(&pid); 
    } 

    return 0; 
} 

See output

3

В вашем примере кода используется возвращаемое значение fork(), чтобы различать родительский и дочерний. Он продолжает итерацию в родительском (предположим, что fork() не сообщает об ошибке), и он exit() s без повторения (после испускания некоторого вывода) в дочернем элементе. Это совершенно обычная процедура.

То, что вы предлагаете сделать, не очень отличается; то, что вы описываете, в основном просто меняет роли родителя и ребенка. В самом деле, у вас есть более простая работа, потому что каждому родителю требуется только wait() для одного ребенка. Он может делать это либо внутри цикла, либо снаружи, при условии, что если последний ребенок wait() s, то он должен ожидать, что вызов указывает на ошибку из-за того, что у этого ребенка не было никаких собственных детей. Однако, если родитель не делает exit() или return изнутри цикла, тогда ему нужно вырваться, а не итерировать дальше.

2

Эта задача аналогична преобразованию итеративного решения в рекурсивное решение. Первый шаг - удалить цикл for. А затем изменить код ребенка, чтобы каждый ребенок:

  1. печатает его сообщение
  2. обновляет переменную счетчика, и если значение счетчика меньше макс
  3. FORKS нового ребенка
  4. ждет его ребенок

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

+1

Конечно, можно рекурсивно реализовать желаемое поведение, но любой рекурсивный алгоритм может быть преобразован в итеративный (без изменения наблюдаемого поведения) и * наоборот *. Поэтому, является ли решение итеративным или рекурсивным, кажется, красная селедка. –

+1

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