Thanks to Adam Powers for the framework used for this demo program
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <signal.h>
/* see http://www.dinkumware.com/htm_cl/signal.html for more on
* signal handling
*/
#define DEFAULT_ITERS 10
#define DEFAULT_NUM_PROCS 10
#define DEBUG
#ifdef DEBUG
#define debugf(fmt, arg...) {fprintf (stdout, fmt, ##arg);}
#else /* not DEBUG */
#define debugf(fmt, arg...) {}
#endif /* DEBUG */
#define errorf(fmt, arg...) fprintf (stdout, fmt, ##arg)
/* Forward Definition
*/
void child_body(long iters);
void sig_handler(int signal);
void core_dump(int signal);
int main(int argc, char *argv[])
{
/* Number of iterations a child will do
*/
long iters = DEFAULT_ITERS;
/* Number of child processes we'll create
*/
int num_procs = DEFAULT_NUM_PROCS;
int i;
int errors = 0;
int pid, status;
double total_time;
struct timeval start, end;
/* setup signal handlers
*/
signal (SIGUSR2, sig_handler);
signal (SIGSEGV, core_dump);
/* check the command line arguments
*/
if (argc >= 2)
{ num_procs = atoi(argv[1]);
iters = atol(argv[2]);
}
else
{ printf("Usage: multiproc [# processes] [# iterations]\n");
}
printf("Doing %i processes, %i iterations each\n", num_procs, iters);
/* start the timer
*/
gettimeofday(&start, NULL);
/* branch off child processes
*/
for (i=0; i<num_procs; ++i)
{ pid = fork();
/* Am I the child?
*/
if (pid == 0)
{ child_body(iters);
return 0;
}
}
/* wait for each child to return
*/
for (i=0; i<num_procs; ++i)
{ pid = wait(&status);
errors += (status >> 8);
if (errors)
{
/* signal all our children
*/
errorf ("*** ERROR - killing children ***\n");
printf("child %d returned status=%d\n", pid, status);
killpg (getpgrp(), SIGUSR2);
}
}
/* stop the timer
*/
gettimeofday(&end, NULL);
total_time =
(end.tv_sec + (end.tv_usec * 0.000001)) -
(start.tv_sec + (start.tv_usec * 0.000001));
printf("\nResults\n");
printf("-------\n");
printf("Number of children: %d\n", num_procs);
printf("Iterations per child: %d\n", iters);
printf("Total iterations: %d\n", iters*num_procs);
printf("Total time for test: %f\n", total_time);
printf("Time / iteration: %f\n",
total_time / (double) (num_procs * iters));
return 0;
}
void sig_handler (int signal)
{
if (signal != SIGUSR2)
{
errorf ("sig handler got signal %d, ignored\n", signal);
}
exit (1);
}
void core_dump (int signal)
{
errorf ("child %d died!\n", getpid());
exit (1);
}
void child_body(long iters)
{
long i;
/* If an error code other than '0' is returned, we
* indicate an error happened and the parent process
* will kill all the children
*/
int errorCode = 0;
debugf ("%d is in process group %d\n", getpid(), getpgid (0));
for (i=0; i < iters; ++i)
{
/* do the iteration body here
*/
}
exit(errorCode);
}
Alternate code for
wait
bool done = false;
int status;
while(!done)
{ cout << "wait start" << endl;
// wait with WNOHANG as last arg to not block
pid_t child_pid = waitpid(-1, &status, 0);
if (child_pid > 0)
{ if (WIFEXITED(status))
{ cout << "child " << child_pid <<
" terminated normally" << endl;
}
if (WCOREDUMP(status))
{ cout << "child " << child_pid <<
" core dumped" << endl;
}
if (WIFSIGNALED(status))
{ cout << "child " << child_pid <<
" terminated from uncaught signal" <<
WTERMSIG(status) << endl;
}
if (WIFSIGNALED(status))
done = true;
}
else if (child_pid < 0)
{ cout << "some kind of error happened during 'waitpid'"
<< endl;
done = true;
}
}
--
MattWalsh - 02 Jan 2002