Multiple Children Examples

  • Waiting for multiple children #3: (fork-multiwait2.c)
  • 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 1Output 2Output 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.