CodeSammich
CodeSammich

Reputation: 206

Wait() runs twice?

In my code below, I'm running a parent process which forks off into two child processes. After child(getpid());, both children exit with a status.

However, when I run the parent process, it somehow always decides to run the parent section twice (sets two different pid values), and I just can't get it to run just once. Is there a way to make wait stop after getting one value?

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>

void child(int n) { //n: child pid
  printf("\nPID of child: %i \n", n);

  //random number rand
  int randFile = open("/dev/random", O_RDONLY);
  int r;

  if(rand < 0)
    printf("ERROR: %s\n", strerror(errno));
  else {
    unsigned int seed;
    read(randFile, &seed, 4); //&rand is a pointer, 4 bytes
    int randClose = close(randFile);

    srand(seed); //seeds rand() with random from /dev/random
    r = rand();

    if(randClose < 0)
      printf("ERROR: %s\n", strerror(errno));

    //range between 5 and 20 seconds
    r = r % 20;
    if( r < 5)
      r = 5;
  }
  //  printf("\n%i\n", r);
  sleep(r);
  //  sleep(1);
  printf("\n child with pid %i FINISHED\n", n);

  exit( r );
}

int main() {
  printf("\nPREFORK\n");

  int parentPID = getpid();

  int child0 = fork();
  if(child0 < 0)
    printf("ERROR: %s\n", strerror(errno));

  int child1 = fork();
  if(child1 < 0)
    printf("\nERROR: %s\n", strerror(errno));

  if(getpid() == parentPID)
    printf("\nPOSTFORK\n");

  //if children
  if(child1 == 0) //using child1 as child-testing value b/c when child1 is set, both children are already forked
    child(getpid());

  int status;
  int pid = wait(&status);

  //parent
  if(getpid() != 0) {
    if( pid < 0)
      printf("\nERROR: %s\n", strerror(errno));
    if ( pid > 0 && pid != parentPID) {
      printf("\nPID of FINISHED CHILD: %i\n Asleep for %i seconds\n", pid, WEXITSTATUS(status));
      printf("PARENT ENDED. PROGRAM TERMINATING");
    }
  }
  return 0;
}

Upvotes: 0

Views: 786

Answers (1)

hexasoft
hexasoft

Reputation: 677

The parent is doing:

int child0 = fork();  // + test if fork failed
int child1 = fork();  // + test if fork failed

First you only have the parent. After 1st fork you have the parent and the 1st child, both at the same execution point, so just before the next fork. So just after that the parent re-creates a child, and the 1st child creates its own child (and will act like the parent).

You have to use if/else so that you are sure that the child don't fork. i.e.:

child0 = fork();  // add check for errors
if (child0 == 0) {
  // the 1st child just have to call that
  child(getpid());
  exit(0);
}
// here we are the parent
child1 = fork();
if (child1 == 0) {
  // the 2nd child just have to call that
  child(getpid());
  exit(0);
}

You can do that differently, of course, this is just an example. The main point is to not call fork() within the child.

Upvotes: 2

Related Questions