web-dev-qa-db-ja.com

fork()によって呼び出されたすべての子プロセスが完了するまで待つ方法は?

私はいくつかのプロセスをforkしていて、タスク全体を完了するのにかかる時間、つまりforkされたすべてのプロセスが完了するまでの時間を測定したいと思います。すべての子プロセスが終了するまで親プロセスを待機させる方法を教えてください。タイマーを適切なタイミングで停止させたい。

これが私が使用するコードです:

#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
18
Kamil Zadora

"else // parent"という行の後のすべてをforループの外に移動します。 forkのループの後、waitpidで別のforループを実行し、次にクロックを停止して残りを実行します。

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配列で検索してインデックスを取得するコードを追加できます。

22
Steve Jessop

最も簡単な方法は、

_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)も参照してください。

13
gnud

すべての子が考慮されるまで、ループ内でwait(またはwaitpid)を呼び出します。

この場合、すべてのプロセスはいずれにせよ同期していますが、最初に使用可能なプロセスの状態が変化すると元に戻るため、一般に、より多くの作業を実行できる場合(ワーカープロセスプールなど)には待機することをお勧めします。

4
Chris Morley

私は システムコールを待つ があなたが探しているものを達成すると信じています。

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

正しい順序で待機することはありませんが、最後の子が死亡するとすぐに停止します。

0
BCS