2010-04-25 43 views
27

Necesito usar las funciones fork() y wait() para completar una tarea. Estamos modelando comportamientos no deterministas y necesitamos que el programa se bifurque() si hay más de una transición posible.fork() y wait() con dos procesos secundarios

Para intentar averiguar cómo funciona el fork y esperar, acabo de hacer un programa simple. Creo que ahora entiendo cómo funcionan las llamadas y estaría bien si el programa solo se bifurcara una vez porque el proceso principal podría usar el estado de salida del proceso hijo único para determinar si el proceso secundario alcanzó el estado de aceptación o no.

Como puede ver en el código que sigue, quiero ser capaz de manejar situaciones donde debe haber más de un proceso secundario. Mi problema es que parece que solo puede establecer el estado usando una función _exit una vez. Entonces, como en mi ejemplo, el estado de salida que el proceso principal prueba muestra que el primer proceso hijo emitió 0 como estado de salida, pero no tiene información sobre el segundo proceso secundario.

Probé simplemente no _exit() - en un rechazo, pero luego ese proceso hijo continuaría, y en efecto parece que hay dos procesos principales.

Disculpe por el gofre, pero le agradecería a alguien que me dijera cómo el proceso de mis padres podría obtener la información de estado en más de un proceso secundario, o me alegra que el proceso solo advierta aceptar estado de el niño procesa, pero en ese caso tendría que salir exitosamente de los procesos secundarios que tienen un estado de rechazo.

Mi código de prueba es el siguiente:

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

int main(void) { 

    pid_t child_pid, wpid, pid; 
    int status = 0; 
    int i; 

    int a[3] = {1, 2, 1}; 
    for(i = 1; i < 3; i++) { 
     printf("i = %d\n", i); 
     pid = getpid(); 
     printf("pid after i = %d\n", pid); 
     if((child_pid = fork()) == 0) { 
      printf("In child process\n"); 
      pid = getpid(); 
      printf("pid in child process is %d\n", pid); 
      /* Is a child process */ 
      if(a[i] < 2) { 
       printf("Should be accept\n"); 
       _exit(1); 
      } else { 
       printf("Should be reject\n"); 
       _exit(0); 
      } 
     } 
    } 

    if(child_pid > 0) { 
     /* Is the parent process */ 
     pid = getpid(); 
     printf("parent_pid = %d\n", pid); 
     wpid = wait(&status); 
     if(wpid != -1) { 
      printf("Child's exit status was %d\n", status); 
      if(status > 0) { 
       printf("Accept\n"); 
      } else { 
       printf("Complete parent process\n"); 
       if(a[0] < 2) { 
        printf("Accept\n"); 
       } else { 
        printf("Reject\n"); 
       } 
      } 
     } 
    } 
    return 0; 
} 

Respuesta

35

Me parece que el problema básico es que tiene una llamada wait() en lugar de un bucle que espera hasta que no haya más hijos. También solo espera si el último fork() es exitoso en lugar de si al menos un fork() es exitoso.

Solo debe usar _exit() si no desea operaciones normales de limpieza, como vaciar cadenas de archivos abiertos, incluido stdout. Hay ocasiones para usar _exit(); Este no es uno de ellos. (En este ejemplo, también podría, por supuesto, hacer que los niños regresen directamente en lugar de llamar al exit() directamente, ya que regresar de main() es equivalente a salir con el estado devuelto. Sin embargo, con mayor frecuencia estaría haciendo el bifurcación y así sucesivamente en un función que no sea main(), y luego exit() es a menudo apropiado.)


hackeado, versión simplificada de su código que le da el diagnóstico que me gustaría. Tenga en cuenta que su bucle for saltó el primer elemento de la matriz (el mío no).

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

int main(void) 
{ 
    pid_t child_pid, wpid; 
    int status = 0; 
    int i; 
    int a[3] = {1, 2, 1}; 

    printf("parent_pid = %d\n", getpid()); 
    for (i = 0; i < 3; i++) 
    { 
     printf("i = %d\n", i); 
     if ((child_pid = fork()) == 0) 
     { 
      printf("In child process (pid = %d)\n", getpid()); 
      if (a[i] < 2) 
      { 
       printf("Should be accept\n"); 
       exit(1); 
      } 
      else 
      { 
       printf("Should be reject\n"); 
       exit(0); 
      } 
      /*NOTREACHED*/ 
     } 
    } 

    while ((wpid = wait(&status)) > 0) 
    { 
     printf("Exit status of %d was %d (%s)\n", (int)wpid, status, 
       (status > 0) ? "accept" : "reject"); 
    } 
    return 0; 
} 

Ejemplo de salida (MacOS X 10.6.3):

parent_pid = 15820 
i = 0 
i = 1 
In child process (pid = 15821) 
Should be accept 
i = 2 
In child process (pid = 15822) 
Should be reject 
In child process (pid = 15823) 
Should be accept 
Exit status of 15823 was 256 (accept) 
Exit status of 15822 was 0 (reject) 
Exit status of 15821 was 256 (accept) 
+0

Ok. Entiendo. Muchas gracias por su respuesta. – Joe

+0

Gracias de nuevo por su tiempo. Eso es genial. Produje una versión de trabajo destrozada después de tu publicación inicial, pero la tuya es mucho más ordenada. Saludos – Joe

+0

@Joe si esta respuesta fue la más útil para usted, entonces debe aceptarla haciendo clic en la marca de verificación a la izquierda. –

8

Ponga su función de espera() en un bucle y esperar a que todos los procesos hijos. La función de espera devolverá -1 y errno será igual a ECHILD si no hay más procesos secundarios disponibles.

+0

Grande. Entiendo. Muchas gracias. – Joe

1

brillante ejemplo Jonathan Leffler, para hacer su trabajo de código en SLES, tenía que añadir una cabecera adicional para permitir que el objeto pid_t :)

#include <sys/types.h> 
+0

Eso es muy extraño ... POSIX 2008 y todos los demás sistemas Linux que he encontrado no necesitan el encabezado ''. Hay funciones en '' (como 'getpid()') que requieren el tipo en su declaración, por lo que '' no necesita ser incluido explícitamente. ¿Puedes indicar las opciones del compilador que estabas utilizando que necesitaban '#include '? –

+0

@JonathanLeffler Sé que es un comentario antiguo, pero SLES es más antiguo que el resto. Es como EL de RedHat. Esa es la razón, supongo. – Shiki

Cuestiones relacionadas