2009-11-03 21 views
15

Así que tengo esta función que teje N número de procesos hijos. Sin embargo, parece estar bifurcando más de lo especificado. ¿Puedes decirme qué estoy haciendo mal? GraciasProblema al horquillar fork() múltiples procesos 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 llamada principal I:

forkChildren(5); 

estoy esperando el siguiente resultado:

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 

Pero en cambio me sale el siguiente:

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

Ahora veo. Acabo de poner la salida (0); después de que cada niño imprima su información. – user69514

Respuesta

14

La llamada fork() genera un nuevo proceso que comienza su ejecución exactamente en el mismo punto donde se produjo la horquilla. Por lo tanto, parece que el tenedor "vuelve dos veces"

Lo que está sucediendo aquí es que su llamada a fork() regresa dos veces, por lo tanto el proceso principal y el secundario continúan en bucle y generando nuevos procesos. Cada hijo (tanto del padre original como del hijo) vuelve a duplicar, duplicando repetidamente el número de procesos ...

+0

No se está duplicando. Los niños todavía están incrementándose en el ciclo, por lo que cada uno de la segunda generación solo creará cuatro nietos, * no * 5. Es una especie de factorial. Pero, aparte de ese * minor * nitpick, buena respuesta. – paxdiablo

+0

@paxdiablo: El niño incrementa i, pero solo su copia local. No tiene ningún efecto en la copia de i de los padres. –

1

Cada niño pr Ocess recoge y continúa el ciclo.

En otras palabras, niño 1 se genera y continúa con iteración # 2 de bucle etc.

Cuando se bifurca un proceso, se hace una copia del proceso actual: el proceso hijo resultante continúa la ejecución después de que el tenedor() llamada. Es por eso que debes cuidar el código de retorno en tu lógica.

15

Cuando usted fork un proceso, básicamente termina con dos (casi) copias exactas del proceso y ambos de ellos continuará funcionando.

Entonces, lo que está sucediendo es que los propios niños continúan el ciclo en el propio espacio de proceso (después de que imprimen su salida) y como el padre que lo está haciendo. Y, de hecho, debido a que estos niños también bifurcan, los nietos también continuarán desde ese punto. Estoy seguro de que hay una fórmula para averiguar cuántos niños terminas (¡probablemente algo así como N!) Pero no tengo la energía para resolverlo en este momento. Es mejor usar la siguiente solución.

La forma de distinguir entre padre e hijo es el valor de retorno de fork.

  • Si obtiene un -1, usted es el padre y el fork falló.
  • Si vuelve a cero, usted es el niño.
  • Si obtiene un número positivo, usted es el padre y ese número es el PID secundario (para que pueda manipularlo o wait para ello).

Aquí hay algo de código de prueba:

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

y alguna salida para mostrar lo que está sucediendo:

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

Se ha cambiado para aclarar. – paxdiablo

+0

Estoy ayudando a un amigo con una asignación de sistema operativo y la función anterior funciona bien, gracias! –

1

En este ejercicio que haría uso de la recursividad en lugar de un bucle. De esta forma, puede hacer que las instrucciones fork() se llamen varias veces, pero solo en una de las dos copias del proceso. Puede hacer que el proceso hijo engendre otro proceso secundario, por lo tanto, tener abuelos, bisabuelos, etc. o puede llamar al tenedor() del lado de los padres, tener un solo "padre" y varios hijos. Esta es una muestra de código que implementa la última solución:

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