Как дождаться завершения всех дочерних процессов, вызванных fork()?

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

Вопрос

Я разветвляю несколько процессов и хочу измерить, сколько времени потребуется для выполнения всей задачи, то есть когда все разветвленные процессы будут завершены.Подскажите, пожалуйста, как заставить родительский процесс ждать завершения всех дочерних процессов?Я хочу быть уверен, что остановлю таймер в нужный момент.

Вот код, который я использую:

#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
Это было полезно?

Решение

Я бы переместил все после строки «else //parent» вниз, за ​​пределы цикла for.После цикла вилок выполните еще один цикл 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, вам придется соответствующим образом изменить проверку ошибок.

Альтернатива использованию ожидания:

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 и возврата индекса.

Другие советы

Самый простой способ - это сделать

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) .

Вызовите wait (или waitpid) в цикле, пока не будут учтены все дочерние элементы.

В этом случае все процессы в любом случае синхронизируются, но в общем случае предпочтение отдается ожиданию, когда можно выполнить больше работы (например, пул рабочих процессов), поскольку оно будет возвращаться при изменении первого доступного состояния процесса.

Я полагаю, что системный вызов wait выполнит то, что вы ищете.

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

Он не будет ждать в правильном порядке, но остановится вскоре после смерти последнего ребенка.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top