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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/279729/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 16:43:07  来源:igfitidea点击:

How to wait until all child processes called by fork() complete?

c++linuxgccparallel-processing

提问by Kamil Zadora

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

采纳答案by Steve Jessop

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:

我会将“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

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 supposedto 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 数组中查找它并取回索引。

回答by SoapBox

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

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

回答by Chris Morley

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.

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

回答by gnud

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)

回答by BCS

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.

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