Проблема forking fork() нескольких процессов Unix

Итак, у меня есть эта функция, которая прошивает N число дочерних процессов. Однако, похоже, это больше, чем указано. Можете ли вы сказать мне, что я делаю неправильно? Благодаря

void forkChildren(int nChildren){
    int i;
    for(i = 1; i <= nChildren; i++){
        pid = fork();
        if(pid == 0)          
            printf("I'm a child: %d PID: %d\n",i, getpid());
    }

} 

В основном я звоню:

forkChildren(5);

Я ожидаю следующий вывод:

I'm a child: 1 PID: 2990
I'm a child: 2 PID: 2991
I'm a child: 3 PID: 2992
I'm a child: 4 PID: 2993
I'm a child: 5 PID: 2994

Но вместо этого я получаю следующее:

I'm a child: 1 PID: 2990
I'm a child: 2 PID: 2991
I'm a child: 3 PID: 2992
I'm a child: 4 PID: 2993
I'm a child: 5 PID: 2994
[email protected]:~/directory/$ I'm a child: 2 PID: 2999
I'm a child: 3 PID: 3000
I'm a child: 3 PID: 3001
I'm a child: 4 PID: 3002
I'm a child: 5 PID: 3003
I'm a child: 5 PID: 3004
I'm a child: 4 PID: 3005
I'm a child: 5 PID: 3006
I'm a child: 4 PID: 3007
I'm a child: 5 PID: 3008
I'm a child: 3 PID: 3011
I'm a child: 4 PID: 3012
I'm a child: 4 PID: 3010
I'm a child: 5 PID: 3013
I'm a child: 5 PID: 3014
I'm a child: 5 PID: 3015
I'm a child: 4 PID: 3018
I'm a child: 5 PID: 3019
I'm a child: 5 PID: 3020
I'm a child: 5 PID: 3021
I'm a child: 5 PID: 3023
I'm a child: 5 PID: 3025
I'm a child: 5 PID: 3024
I'm a child: 4 PID: 3022
I'm a child: 5 PID: 3026
I'm a child: 5 PID: 3027

Ответы

Ответ 1

Вызов fork() порождает новый процесс, который начинает свое выполнение в той же точке, где произошла вилка. Итак, похоже, что fork "возвращается дважды"

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

Ответ 2

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

Итак, что происходит, что сами дети продолжают цикл в собственном пространстве процессов (после того, как они печатают свой вывод), а также его родитель. И, фактически, потому что эти дети также разветвляются, внуки также будут продолжать с этого момента. Я уверен, что есть формула для того, чтобы выяснить, сколько детей вы в конечном итоге (возможно, что-то вроде N!), Но у меня нет энергии, чтобы понять это на данный момент. Лучше использовать следующее решение.

Способ узнать разницу между родительским и дочерним является возвращаемым значением из fork.

  • Если вы вернете -1, вы являетесь родителем, а fork не удалось.
  • Если вы вернете нуль, вы - ребенок.
  • Если вы вернете положительное число, вы являетесь родителем, и этот номер является дочерним PID (чтобы вы могли манипулировать им или wait для него).

Вот несколько тестовых кодов:

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

void forkChildren (int nChildren) {
    int i;
    pid_t pid;
    for (i = 1; i <= nChildren; i++) {
        pid = fork();
        if (pid == -1) {
            /* error handling here, if needed */
            return;
        }
        if (pid == 0) {
            printf("I am a child: %d PID: %d\n",i, getpid());
            sleep (5);
            return;
        }
    }
}

int main (int argc, char *argv[]) {
    if (argc < 2) {
        forkChildren (2);
    } else {
        forkChildren (atoi (argv[1]));
    }
    return 0;
}

и некоторый вывод, чтобы показать вам, что происходит:

pax> forktest 5
I am a child: 1 PID: 4188
I am a child: 2 PID: 4180
I am a child: 3 PID: 5396
I am a child: 4 PID: 4316
I am a child: 5 PID: 4260

pax> _

Ответ 3

Каждый дочерний процесс поднимает и продолжает цикл.

Другими словами, ребенок 1 порождается и продолжается с повторением цикла 2 и т.д.

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

Ответ 4

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

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

int nChildren;

void myFork(int n);

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

  // just a check on the number of arguments supplied
  if (argc < 2) {
    printf("Usage: forktest <number_of_children>\n");
    printf("Example: forktest 5 - spawns 5 children processes\n");
    return -1;
  }

  nChildren = atoi(argv[1]);
  // starting the recursion...
  myFork(nChildren-1);
  return 0;
}

// the recursive function
void myFork(int n) {
  pid_t pid;

  pid = fork();

  // the child does nothing but printing a message on screen
  if (pid == 0) {
    printf("I am a child: %d PID: %d\n", nChildren-n, getpid());
    return;
  }

  // if pid != 0, we're in the parent
  // let print a message showing that the parent pid is always the same...
  printf("It always me (PID %d) spawning a new child (PID %d)\n", getpid(), pid);
  // ...and wait for the child to terminate.
  wait(pid);

  // let call ourself again, decreasing the counter, until it reaches 0.
  if (n > 0) {
    myFork(n-1);
  }
}