2009-11-03 12 views
15

Quindi ho questa funzione che forca N numero di processi figlio. Tuttavia sembra che stia biforcando più di quanto specificato. Puoi dirmi cosa sto sbagliando? GrazieProblema forking fork() più processi 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()); 
    } 

} 

In chiamata ho principale:

forkChildren(5); 

mi aspetto il seguente output:

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 

Ma invece ottengo il seguente:

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

Vedo ora. Ho appena messo exit (0); dopo ogni bambino stampa le sue informazioni. – user69514

risposta

14

La chiamata a fork() genera un nuovo processo che inizia la sua esecuzione nello stesso identico punto dove si è verificato il fork. Quindi, sembra che la forcella "ritorni due volte"

Ciò che sta accadendo qui è che la chiamata a fork() restituisce due volte, quindi sia il processo genitore che figlio continuano a ripetere e generare nuovi processi. Ogni bambino (sia del genitore originale che del bambino) quindi si biforca nuovamente, raddoppiando ripetutamente il numero di processi ...

+0

Non proprio raddoppiando. I bambini stanno ancora incrementando i nel ciclo in modo che ognuno della seconda generazione crei solo quattro nipoti, * non * 5. È una forma di fattoriale. Ma, a parte questo * minor * nitpick, buona risposta. – paxdiablo

+0

@paxdiablo: Il figlio incrementa i, ma solo la sua copia locale. Non ha alcun effetto sulla copia del genitore di i. –

1

Ogni bambino l'occhiata riprende e continua il ciclo.

In altre parole, bambino 1 viene generato e continua con iterazione # 2 riccio ecc

Quando un processo viene biforcuta, viene creata una copia del processo corrente: il processo figlio risultante continua l'esecuzione dopo la biforcazione() chiama. Ecco perché devi prenderti cura del codice di ritorno nella tua logica.

15

Quando si esegue il processo fork, si finisce fondamentalmente con due (quasi) copie esatte del processo ed entrambi di loro continuerà a correre.

Quindi, quello che sta succedendo è che i bambini stessi stanno continuando il ciclo nel proprio spazio del processo (dopo aver stampato l'output) e come il genitore che lo fa. E, infatti, poiché anche questi bambini stanno biforcandosi, i nipoti continueranno anche da quel punto. Sono sicuro che c'è una formula per capire in realtà quanti bambini si finiscono con (probabilmente qualcosa come N!), Ma non ho l'energia per capirlo al momento. Meglio usare la seguente soluzione.

Il modo per rilevare la differenza tra genitore e figlio è il valore restituito da fork.

  • Se si ottiene un -1, si è il genitore e il fork non è riuscito.
  • Se torni a zero, sei il bambino.
  • Se si ottiene un numero positivo, si è il genitore e tale numero è il PID figlio (in modo da poterlo manipolare o wait per esso).

Ecco alcuni codice di prova:

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

e qualche uscita visualizzare ciò che sta accadendo:

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

modificato per chiarire. – paxdiablo

+0

Sto aiutando un amico con un assegnamento del sistema operativo e la funzione di cui sopra funziona bene, grazie! –

1

In questo esercizio mi piacerebbe utilizzare la ricorsione, piuttosto che un ciclo for. In questo modo è possibile avere l'istruzione fork() chiamata più volte ma solo su una delle due copie del processo. Puoi fare in modo che il processo figlio generi un altro processo figlio, quindi avere nonni, bisnonni, ecc. Oppure puoi chiamare il fork() sul lato genitore, con un singolo "padre" e più figli. Questo è un esempio di codice che implementa la seconda soluzione:

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