views:

3058

answers:

5

Hi,

I am forking a number of processes and I want to measure how long those it take to to complete the whole task, that is when all processes forked are completed. Please advise how to make the parent process to wait until all child process are terminated? I want tu make sure that I stop the time watch in 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

exit(0);// The End
}
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
+3  A: 

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

SoapBox
Note that wait() only waits for one child process - therefore, you must call wait() as many times as there are children. Alternatively, you can use waitpid() to wait for a specific child, but again you'd have to do this for every child.
Adam Rosenfield
+3  A: 

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

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.

Chris Morley
Could you please provide me with a code sample? I must admit I do not fully understand the flags I should use...
Kamil Zadora
+4  A: 

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 som error checking, this becomes

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

gnud
you still need to account for the number of child processes
BCS
Nah. When there are no more children, wait will return -1 and errno will be set to ECHILD. Not optimal, but for his use it should be sufficient.
gnud
Doesn't this abort if the parent process receives and handles a non-fatal signal, thus interrupting the wait? Is that desirable?
Steve Jessop
If it isn't desirable, then ignore the signals first. That's not unique to process handling--
gnud
+1  A: 
for(int i = 0; i<pidCount; i++
    while(0<waitpid(pids[i],NULL,0));
// won't wait in right order but stops soon after last child dies
BCS
+2  A: 

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

An alternative using wait:

while (true) {
    int status;
    pid_t done = wait(&status);
    if (done == -1) {
        if (errno == ECHLD) 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.

Steve Jessop
Thanks! Works like a charm.
Kamil Zadora