¿Cómo esperar hasta que se completen todos los procesos secundarios llamados por fork ()?

StackOverflow https://stackoverflow.com/questions/279729

Pregunta

Estoy bifurcando una serie de procesos y quiero medir cuánto tiempo se tarda en completar toda la tarea, es decir, cuando se completan todos los procesos bifurcados. ¿Indicar cómo hacer que el proceso principal espere hasta que todos los procesos secundarios finalicen? Quiero asegurarme de detener el temporizador en el momento adecuado.

Aquí está el código que uso:

#include <iostream>
#include <string>
#include <fstream>
#include <sys/time.h>
#include <sys/wait.h>

using namespace std;

struct timeval first,  second,  lapsed;
struct timezone tzp; 

int main(int argc, char* argv[])// query, file, num. of processes.
{

    int pCount = 5; // process count

    gettimeofday (&first, &tzp); //start time

    pid_t* pID = new pid_t[pCount];

    for(int indexOfProcess=0; indexOfProcess<pCount; indexOfProcess++)
    {
        pID[indexOfProcess]= fork();

        if (pID[indexOfProcess] == 0)                // child
        {
            // code only executed by child process

            // magic here

            // The End
            exit(0);
        }
        else if (pID[indexOfProcess] < 0)    // failed to fork
        {
            cerr << "Failed to fork" << endl;
            exit(1);
        }
        else                         // parent
        {
            // if(indexOfProcess==pCount-1) and a loop with waitpid??

            gettimeofday (&second, &tzp); //stop time
            if (first.tv_usec > second.tv_usec)
            {
                second.tv_usec += 1000000;
                second.tv_sec--;
            }

            lapsed.tv_usec = second.tv_usec - first.tv_usec;
            lapsed.tv_sec = second.tv_sec - first.tv_sec; 

            cout << "Job performed in " <<lapsed.tv_sec << " sec and " << lapsed.tv_usec    << " usec"<< endl << endl;

        }

    }//for

}//main
¿Fue útil?

Solución

Movería todo después de la línea '' else // parent '' abajo, fuera del bucle for. Después del bucle de horquillas, haga otro bucle for con waitpid, luego detenga el reloj y haga el resto:

for (int i = 0; i < pidCount; ++i) {
    int status;
    while (-1 == waitpid(pids[i], &status, 0));
    if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
        cerr << "Process " << i << " (pid " << pids[i] << ") failed" << endl;
        exit(1);
    }
}

gettimeofday (&second, &tzp); //stop time

Supuse que si el proceso secundario no puede salir normalmente con un estado de 0, entonces no completó su trabajo y, por lo tanto, la prueba no pudo producir datos de tiempo válidos. Obviamente, si se supone que los procesos secundarios supuestamente deben ser eliminados por señales o salir de estados de retorno que no sean 0, entonces deberá cambiar la verificación de error en consecuencia.

Una alternativa usando wait:

while (true) {
    int status;
    pid_t done = wait(&status);
    if (done == -1) {
        if (errno == ECHILD) break; // no more child processes
    } else {
        if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
            cerr << "pid " << done << " failed" << endl;
            exit(1);
        }
    }
}

Este no le dice qué proceso en secuencia falló, pero si le importa, puede agregar código para buscarlo en la matriz de pids y recuperar el índice.

Otros consejos

El método más simple es hacer

while(wait() > 0) { /* no-op */ ; }

Esto no funcionará si wait () falla por alguna razón que no sea el hecho de que no quedan hijos. Entonces, con alguna comprobación de errores, esto se convierte en

int status;
[...]
do {
    status = wait();
    if(status == -1 && errno != ECHILD) {
        perror("Error during wait()");
        abort();
    }
} while (status > 0);

Consulte también la página del manual wait (2) .

Llame a wait (o waitpid) en un bucle hasta que todos los niños sean contabilizados.

En este caso, todos los procesos se sincronizan de todos modos, pero en general se prefiere esperar cuando se puede hacer más trabajo (por ejemplo, grupo de procesos de trabajo), ya que volverá cuando cambie el primer estado de proceso disponible.

Creo que la llamada al sistema de espera logrará lo que está buscando.

for (int i = 0; i < pidCount; i++) {
    while (waitpid(pids[i], NULL, 0) > 0);
}

No esperará en el orden correcto, pero se detendrá poco después de que muera el último niño.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top