c++ - pthread - ¿Cómo esperar hasta que se completen todos los procesos secundarios llamados por fork()?
programacion multihilo en c (5)
Estoy horcando una serie de procesos y quiero medir cuánto tiempo lleva completar toda la tarea, es decir, cuando se completan todos los procesos bifurcados. Indique cómo hacer que el proceso principal espere hasta que finalicen todos los procesos secundarios. Quiero asegurarme de detener el cronómetro en el momento correcto.
Aquí está como un 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
Creo que la llamada al sistema de espera logrará lo que está buscando.
Espera de llamada (o waitpid) en un bucle hasta que se tengan en cuenta todos los niños.
En este caso, todos los procesos se sincronizan de todos modos, pero en general se prefiere esperar cuando se puede realizar más trabajo (por ejemplo, grupo de procesos de trabajo), ya que volverá cuando cambie el primer estado del proceso disponible.
Movería todo después de la línea "else // parent" hacia abajo, fuera del ciclo for. Después del bucle de las horquillas, haga otro ciclo 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 hijo no puede salir normalmente con un estado de 0, entonces no completó su trabajo y, por lo tanto, la prueba no pudo generar datos de temporización válidos. Obviamente, si se supone que los procesos secundarios deben ser eliminados por señales, o salir de estados de retorno que no sean 0, entonces deberá cambiar la verificación de errores en consecuencia.
Una alternativa usando espera:
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 te dice qué proceso en secuencia falló, pero si te importa, entonces puedes agregar código para buscarlo en la matriz pids y recuperar el índice.
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.
El método más simple es hacer
while(wait() > 0) { /* no-op */ ; }
Esto no funcionará si wait()
falla por algún motivo que no sea el hecho de que no quedan niños. Entonces con alguna comprobación de errores, esto se convierte
int status;
[...]
do {
status = wait();
if(status == -1 && errno != ECHILD) {
perror("Error during wait()");
abort();
}
} while (status > 0);
Ver también la wait(2)
página del manual wait(2)
.