Use this technique if the parent process has other work to do while the children are working. If the parent has nothing to do (but wait for the children), DO NOT UNDER ANY CIRCUMSTANCES use this technique. There are various ways to wait for multiple children, this just demonstrates one way.
#include <stdio.h> /* printf */
#include <stdlib.h> /* exit */
#include <unistd.h> /* fork, getpid, sleep */
#include <sys/wait.h> /* wait, waitpid */
/* Doesn't return */
void dochild(int count)
{
int pid = getpid();
printf("[%i] child process\n", pid);
sleep(count);
printf("[%i] child exiting\n", pid);
exit(count * 10);
}
int main(void)
{
#define COUNT 3
int running = COUNT;
int i, cpid[COUNT], terminated[COUNT] = {0};
int ppid = getpid();
printf("parent pid = %i\n", ppid);
for (i = 0; i < COUNT; i++)
{
cpid[i] = fork();
if (cpid[i] == 0) /* child process is always 0 */
dochild(i);
}
/* parent process is non-zero (child's pid) */
printf("waiting for children\n");
while (running)
{
for (i = 0; i < COUNT; i++)
{
int status;
/*printf("waiting for child pid: %i\n", cpid[i]);*/
/* If the parent has work to do while waiting, do it here...*/
if (!terminated[i])
{
/*printf("child pid: %i not terminated\n", cpid[i]);*/
if (waitpid(cpid[i], &status, WNOHANG))
{
if (WIFEXITED(status))
{
printf("[%i] child ended normally: %i\n", cpid[i], WEXITSTATUS(status));
running--;
terminated[i] = 1;
}
}
}
}
}
printf("children terminated\n");
printf("parent exiting\n");
return 0;
}
Output 1 Output 2 Output 3 parent pid = 1132 [928] child process [2456] child process [928] child exiting waiting for children [928] child ended normally: 0 [3628] child process [2456] child exiting [2456] child ended normally: 10 [3628] child exiting [3628] child ended normally: 20 children terminated parent exiting parent pid = 3956 [3940] child process [3940] child exiting [3564] child process waiting for children [2764] child process[3940] child ended normally: 0 [3564] child exiting [3564] child ended normally: 10 [2764] child exiting [2764] child ended normally: 20 children terminated parent exiting parent pid = 948 [1100] child process [2440] child process [1100] child exiting waiting for children[1684] child process [1100] child ended normally: 0 [2440] child exiting [2440] child ended normally: 10 [1684] child exiting [1684] child ended normally: 20 children terminated parent exiting
This example shows the parent waiting on any child to complete, regardless of the order the children complete. (fork-multiwait3.c)
#include <stdio.h> /* fprintf, stdout */
#include <stdlib.h> /* exit */
#include <unistd.h> /* fork, getpid, sleep */
#include <sys/wait.h> /* wait, waitpid */
void dochild(int id, int count)
{
int pid = getpid();
fprintf(stdout,"[%i] child process\n", pid);
sleep(count);
fprintf(stdout, "[%i] child exiting\n", pid);
exit(id * 10);
}
int main(void)
{
#define COUNT 3
int running = COUNT;
int i, cpid[COUNT], child;
int ppid = getpid();
int counts[] = {3, 2, 1};
fprintf(stdout, "parent pid = %d\n", ppid);
for (i = 0; i < COUNT; i++)
{
cpid[i] = fork();
if (cpid[i] == 0) /* child process is always 0 */
dochild(i, counts[i]);
}
/* parent process is non-zero (child's pid) */
fprintf(stdout, "waiting for children\n");
while (running > 0)
{
int status;
/* wait for any child */
if ( (child = waitpid(-1, &status, WNOHANG)) != 0)
{
if (WIFEXITED(status))
fprintf(stdout, "[%i] child ended normally: %i\n", child, WEXITSTATUS(status));
else
fprintf(stdout, "[%i] child ended abnormally: %i\n", child, WEXITSTATUS(status));
running--;
}
/* If the parent has work to do while waiting, do it here...*/
}
fprintf(stdout, "children terminated\n");
fprintf(stdout, "parent exiting\n");
return 0;
}
Output parent pid = 1524 [1525] child process waiting for children [1527] child process [1528] child process [1528] child exiting [1528] child ended normally: 20 [1527] child exiting [1527] child ended normally: 10 [1525] child exiting [1525] child ended abnormally: 0 children terminated parent exiting
DO NOT use the technique above (WNOHANG) for any assignments in the class unless specifically instructed to do so. Doing so will cause you to lose significant points (most likely a 0 on the assignment, plus, Mead will KICK YOUR ASS). I'm only showing this technique so that, in the future (outside of this class), you may find that you need this capability. Doing this when the parent has nothing to do will effectively disable one of the cores on your CPU and slow down the entire system.
If you don't understand that last sentence, then you definitely shouldn't use this technique until you do understand it.