如何等待fork()调用的所有子进程完成?

时间:2022-12-07 22:02:51

I am forking a number of processes and I want to measure how long it takes to complete the whole task, that is when all processes forked are completed. Please advise how to make the parent process wait until all child processes are terminated? I want to make sure that I stop the timer at the right moment.

我正在分配许多进程,我想测量完成整个任务所需的时间,即分叉完成所有进程的时间。请告知如何让父进程等待直到所有子进程终止?我想确保在合适的时刻停止计时器。

Here is as a code I use:

这是我使用的代码:

#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

5 个解决方案

#1


21  

I'd move everything after the line "else //parent" down, outside the for loop. After the loop of forks, do another for loop with waitpid, then stop the clock and do the rest:

我会在for循环之外的“else // parent”行之后移动所有内容。在forx循环之后,用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

I've assumed that if the child process fails to exit normally with a status of 0, then it didn't complete its work, and therefore the test has failed to produce valid timing data. Obviously if the child processes are supposed to be killed by signals, or exit non-0 return statuses, then you'll have to change the error check accordingly.

我假设如果子进程无法正常退出状态为0,则它​​无法完成其工作,因此测试无法生成有效的时序数据。显然,如果子进程应该被信号杀死,或者退出非0返回状态,那么你必须相应地更改错误检查。

An alternative using 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);
        }
    }
}

This one doesn't tell you which process in sequence failed, but if you care then you can add code to look it up in the pids array and get back the index.

这个没有告诉你顺序哪个进程失败了,但如果你关心那么你可以添加代码在pids数组中查找并获取索引。

#2


13  

The simplest method is to do

最简单的方法是做

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

This will not work if wait() fails for some reason other than the fact that there are no children left. So with some error checking, this becomes

如果wait()由于某些原因而失败,除了没有留下孩子的事实,这将无法工作。因此,通过一些错误检查,这就变成了

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

See also the manual page wait(2).

另请参见手册页wait(2)。

#3


4  

Call wait (or waitpid) in a loop until all children are accounted for.

在循环中调用wait(或waitpid),直到考虑所有子节点。

In this case, all processes are synchronizing anyway, but in general wait is preferred when more work can be done (eg worker process pool), since it will return when the first available process state changes.

在这种情况下,所有进程无论如何都是同步的,但一般情况下,当可以完成更多工作(例如工作进程池)时,首选等待,因为它将在第一个可用进程状态更改时返回。

#4


3  

I believe the wait system call will accomplish what you are looking for.

我相信等待系统调用将完成您正在寻找的。

#5


0  

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

It won't wait in the right order, but it will stop shortly after the last child dies.

它不会以正确的顺序等待,但它会在最后一个孩子死后不久停止。

#1


21  

I'd move everything after the line "else //parent" down, outside the for loop. After the loop of forks, do another for loop with waitpid, then stop the clock and do the rest:

我会在for循环之外的“else // parent”行之后移动所有内容。在forx循环之后,用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

I've assumed that if the child process fails to exit normally with a status of 0, then it didn't complete its work, and therefore the test has failed to produce valid timing data. Obviously if the child processes are supposed to be killed by signals, or exit non-0 return statuses, then you'll have to change the error check accordingly.

我假设如果子进程无法正常退出状态为0,则它​​无法完成其工作,因此测试无法生成有效的时序数据。显然,如果子进程应该被信号杀死,或者退出非0返回状态,那么你必须相应地更改错误检查。

An alternative using 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);
        }
    }
}

This one doesn't tell you which process in sequence failed, but if you care then you can add code to look it up in the pids array and get back the index.

这个没有告诉你顺序哪个进程失败了,但如果你关心那么你可以添加代码在pids数组中查找并获取索引。

#2


13  

The simplest method is to do

最简单的方法是做

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

This will not work if wait() fails for some reason other than the fact that there are no children left. So with some error checking, this becomes

如果wait()由于某些原因而失败,除了没有留下孩子的事实,这将无法工作。因此,通过一些错误检查,这就变成了

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

See also the manual page wait(2).

另请参见手册页wait(2)。

#3


4  

Call wait (or waitpid) in a loop until all children are accounted for.

在循环中调用wait(或waitpid),直到考虑所有子节点。

In this case, all processes are synchronizing anyway, but in general wait is preferred when more work can be done (eg worker process pool), since it will return when the first available process state changes.

在这种情况下,所有进程无论如何都是同步的,但一般情况下,当可以完成更多工作(例如工作进程池)时,首选等待,因为它将在第一个可用进程状态更改时返回。

#4


3  

I believe the wait system call will accomplish what you are looking for.

我相信等待系统调用将完成您正在寻找的。

#5


0  

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

It won't wait in the right order, but it will stop shortly after the last child dies.

它不会以正确的顺序等待,但它会在最后一个孩子死后不久停止。