Как дожидаться завершения всех дочерних процессов, вызванных fork()?
Я запускаю ряд процессов, и я хочу измерить, сколько времени потребуется для завершения всей задачи, то есть когда все процессы forked завершены. Пожалуйста, сообщите, как заставить родительский процесс ждать, пока все дочерние процессы не будут завершены? Я хочу, чтобы я остановил таймер в нужный момент.
Вот как код, который я использую:
#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
Ответы
Ответ 1
Я бы переместил все после строки "else//parent" вниз, вне цикла for. После цикла вилок сделайте еще один цикл с waitpid, затем остановите часы и сделайте остальные:
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
Я предположил, что если дочерний процесс не может нормально выйти из состояния 0, то он не завершил свою работу, и поэтому тест не смог создать достоверные данные синхронизации. Очевидно, что если дочерние процессы должны быть убиты сигналами или выходить из не-0 статусов возврата, вам придется соответствующим образом изменить проверку ошибок.
Альтернатива, использующая 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);
}
}
}
Это не говорит вам, какой процесс в последовательности завершился неудачно, но если вам интересно, вы можете добавить код, чтобы просмотреть его в массиве pids и вернуть индекс.
Ответ 2
Самый простой способ - сделать
while(wait() > 0) { /* no-op */ ; }
Это не сработает, если wait()
не удается по какой-либо причине, кроме того, что детей не осталось. Поэтому с некоторой проверкой ошибок это становится
int status;
[...]
do {
status = wait();
if(status == -1 && errno != ECHILD) {
perror("Error during wait()");
abort();
}
} while (status > 0);
См. также страницу руководства wait(2)
.
Ответ 3
Ожидание вызова (или waitpid) в цикле до тех пор, пока не будут учтены все дочерние элементы.
В этом случае все процессы все равно синхронизируются, но в общем случае ожидание предпочтительнее, когда можно сделать больше работы (например, пул рабочих процессов), поскольку он будет возвращаться при изменении первого доступного состояния процесса.
Ответ 4
Я считаю, что wait system call выполнит то, что вы ищете.
Ответ 5
for (int i = 0; i < pidCount; i++) {
while (waitpid(pids[i], NULL, 0) > 0);
}
Он не будет ждать в правильном порядке, но он остановится вскоре после смерти последнего ребенка.