2009-11-03 8 views
15

J'ai donc cette fonction qui forks N nombre de processus enfants. Cependant, il semble être plus forking que spécifié. Pouvez-vous me dire ce que je fais mal? MerciProblème forking fork() plusieurs processus Unix

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()); 
    } 

} 

En principal appel I:

forkChildren(5); 

J'attends la sortie suivante:

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 

Mais au lieu que je reçois le texte suivant:

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 
+2

Je vois maintenant. Je viens de mettre la sortie (0); après chaque enfant imprime ses informations. – user69514

Répondre

14

L'appel fork() engendre un nouveau processus qui commence son exécution au même point où la branche s'est produite. Ainsi, il semble que fork "renvoie deux fois"

Ce qui se passe ici, c'est que votre appel fork() renvoie deux fois, de sorte que le processus parent et enfant continuent à boucler et engendrer de nouveaux processus. Chaque enfant (à la fois du parent et de l'enfant) recommence à zéro, en multipliant par deux le nombre de processus ...

+0

Pas tout à fait doubler. Les enfants continuent à s'incrémenter dans la boucle de sorte que chacun de la deuxième génération ne créera que quatre petits-enfants, * pas * 5. C'est une forme de factoriel. Mais, autre que ce * minuscule * nitpick, bonne réponse. – paxdiablo

+0

@paxdiablo: L'enfant incrémente i, mais seulement sa copie locale. Cela n'a aucun effet sur la copie parentale de i. –

1

Chaque enfant pr ocess reprend et continue la boucle.

En d'autres termes, l'enfant 1 est engendré et continue avec l'itération # 2 de boucle, etc.

Lorsqu'un processus est en forme de fourche, une copie du processus en cours est fait: le processus enfant résultant poursuit son exécution après la fourche() appel. C'est pourquoi vous devez prendre soin du code de retour dans votre logique.

15

Lorsque vous exécutez un processus, vous obtenez deux copies (presque) exactes du processus et les deux d'entre eux continueront à courir.

Donc, ce qui se passe, c'est que les enfants eux-mêmes continuent la boucle dans le propre espace de processus (après avoir imprimé leur sortie) ainsi que comme le fait le parent. Et, en fait, parce que ces enfants sont aussi en train de forger, les petits-enfants continueront à partir de ce point. Je suis sûr qu'il y a une formule pour déterminer combien d'enfants vous finissez avec (probablement quelque chose comme N!) Mais je n'ai pas l'énergie pour le comprendre en ce moment. Mieux vaut utiliser la solution suivante.

La façon de faire la différence entre parent et enfant est la valeur de retour de fork.

  • Si vous obtenez un retour -1, vous êtes le parent et le fork a échoué.
  • Si vous obtenez un zéro, vous êtes l'enfant.
  • Si vous obtenez un nombre positif, vous êtes le parent et ce nombre est le PID enfant (donc vous pouvez le manipuler ou wait pour cela).

est ici un code de test:

#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; 
} 

et une sortie pour vous montrer ce qui se passe:

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> _ 
+0

Modifié pour clarifier. – paxdiablo

+0

J'aide un ami avec une affectation OS et la fonction ci-dessus fonctionne bien, merci! –

1

Dans cet exercice j'utiliser récursion plutôt qu'une boucle. De cette façon, vous pouvez appeler l'instruction fork() plusieurs fois, mais seulement sur l'une des deux copies du processus. Vous pouvez faire en sorte que le processus fils engendre un autre processus enfant, ayant ainsi des grands-parents, des arrière-grands-parents etc. ou vous pouvez appeler fork() du côté parent, ayant un seul "père" et plusieurs enfants. Ceci est un exemple de code qui implémente la dernière solution:

#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's print a message showing that the parent pid is always the same... 
    printf("It's always me (PID %d) spawning a new child (PID %d)\n", getpid(), pid); 
    // ...and wait for the child to terminate. 
    wait(pid); 

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