2009-10-02 39 views
12

En mi programa estoy bifurcando (en paralelo) procesos secundarios en un ciclo while finito y haciendo exec en cada uno de ellos. Quiero que el proceso padre reanude la ejecución (el punto después de este ciclo while) solo después de que todos los hijos hayan terminado. ¿Cómo debo hacer eso?Esperando todos los procesos secundarios antes de que el padre reanude la ejecución UNIX

He intentado varios enfoques. En un enfoque, hice parent pause after loop y envié alguna condición del controlador SIGCHLD solo cuando waitpid devolvió el error ECHILD (no queda ningún hijo) pero el problema al que me enfrento en este enfoque es incluso antes de que el padre haya terminado de bifurcar todos los procesos, retStat se convierte -1

void sigchld_handler(int signo) { 
     pid_t pid; 
     while((pid= waitpid(-1,NULL,WNOHANG)) > 0); 
     if(errno == ECHILD) { 
      retStat = -1; 
     } 
    } 

    **//parent process code** 
    retStat = 1; 
    while(some condition) { 
     do fork(and exec); 
    } 

    while(retStat > 0) 
     pause(); 
//This is the point where I want execution to resumed only when all children have finished 

Respuesta

21

En lugar de llamar waitpid en el manejador de la señal, por qué no crear un bucle en forma de horquilla después de haber todos los procesos de la siguiente manera:

while (pid = waitpid(-1, NULL, 0)) { 
    if (errno == ECHILD) { 
     break; 
    } 
} 

El programa debe colgar en el bucle hasta que no haya más niños. Luego se caerá y el programa continuará. Como una ventaja adicional, el ciclo se bloqueará en waitpid mientras los niños están en ejecución, por lo que no necesita un bucle ocupado mientras espera.

También podría usar wait(NULL) que debería ser equivalente a waitpid(-1, NULL, 0). Si no hay nada más que deba hacer en SIGCHLD, puede configurarlo en SIG_IGN.

+0

Necesito dar la opción WNOHANG porque si hay muchos niños que entregan la señal SIGCHLD casi al mismo tiempo, y dado que las señales no están en cola en UNIX, si uso 0, entonces podré atrapar solo una señal y luego los zombis quedarte alrededor. – avd

+0

Solo para agregar un bit, el -1 se comparará con cualquier pid niño (podría usar WAIT_ANY para mayor claridad también). – amischiefr

+0

@aditya: Los procesos zombies solo esperan que usted llame a wait() (o wait_pid()) en ellos. Tan pronto como lo hagas, desaparecerán, ya sea que hayas captado o no la señal. Entonces, el bucle wait() después del bucle fork() borrará todos los zombies. –

0

Creo que deberías utilizar la llamada waitpid(). Te permite esperar a "cualquier proceso secundario", por lo que si lo haces la cantidad adecuada de veces, deberías estar dorado.

Si eso no funciona (no estoy seguro de las garantías), que podría hacer el enfoque de fuerza bruta sentado en un bucle, haciendo un waitpid() con la opción NOHANG en cada uno de sus hijos PID, y luego retrasar durante un tiempo antes de hacer de nuevo.

+0

Por favor, vea el código, he hecho exactamente lo mismo que dice. – avd

+0

@aditya: Uh, no, mi sugerencia es hacer lo que Jborque sugiere, no dije nada sobre el uso de un manejador de señal. – unwind

Cuestiones relacionadas