0

To fork off X processes and have the parent wait for all, I have the following code:

int maxProcesses = 10;

for (int currentChild = 0; currentChild < maxProcesses; currentChild++) {
    pid_t pid = fork();

    if (pid < 0) {
        // Error
    } else if (pid == 0) {
        // Child
    } else {
        // Parent
        // Should I call waitpid on pid and wait here instead?
    }
}

// Wait for all children
for (int currentChild = 0; currentChild < maxProcesses; currentChild++) {
    wait(NULL);
}

Now I would like to modify the code so that of X total processes, Y are forked off first, and then as they finish, more forks are made till desired total number is reached. I have made some changes to the above code, with some questions.

int totalProcessesToBeForked = 10;
int maxAllowedAtOnce = 5;

for (int currentChild = 0; currentChild < maxAllowedAtOnce; currentChild++) {
    forkChild(currentChild);
}

// Wait for all children
// # How do I modify this to wait for new children forked as well
// # if I move it inside parent, it will make things easier, right?
for (int currentChild = 0; currentChild < maxAllowedAtOnce; currentChild++) {
    wait(NULL);
}

void forkChild(currentChild) {
    pid_t pid = fork();

    if (pid < 0) {
        // Error
    } else if (pid == 0) {
        // Child
    } else {
        // Parent
        // # I think waiting here using waitpid will be better b/c
        // # as new forks are made, parent begins to wait for them
    }
}

I will probably need to keep a count of how many children have been forked and compare it to totalProcessesToBeForked, and fork new ones accordingly.

Updated Code v1:

int maxProcesses = 10;
int maxAllowedAtOnce = 5;

int main(int argc, char* argv[]) {
    // Start timer
    alarm(10);                  // Terminate after 10s
    signal(SIGALRM, onTimeout);
    signal(SIGCHLD, catchChild);

    for (int currentChild = 0; currentChild < maxAllowedAtOnce; currentChild++) {
        forkChild(currentChild);
    }

    // # This sections runs immediately before death of any child is reported
    // # and starts cleanup processes, thus killing any/all running children

    // Completed before timeout
    endTimer = true;
    int timeRemaining = alarm(0);
    if (timeRemaining > 0) {
        printf("\nCompleted w/ %is remaining. Performing cleanup.\n", timeRemaining);

        // Kill children any running child processes, cleanup
        cleanup();
    }

    return 0;
}

void forkChild(currentChild) {
    pid_t pid = fork();

    if (pid < 0) {
        // Error
    } else if (pid == 0) {
        // Child
        execl("/bin/date", "date", 0, 0);
    } else {
        // Parent
        printf("#Log: Started %i.\n", currentChild + 1);
    }
}

void catchChild(int sig) {
    pid_t p;
    int state;
    p=wait(&state);
    printf("Got child %d\n",p);
}

void cleanup() {
    // Cleanup Code
}

Example Run:

enter image description here

Edit #2: http://ideone.com/noUs3m

Ali
  • 558
  • 7
  • 28

1 Answers1

1

Instead of using wait as you have done, you want to look into signal handling to handle the child processes dying.

You add before you start forking, this line

signal(SIGCHLD,catchchild);

and this function to your code

void catchchild(int sig)
  {
  pid_t p;
  int state;
  p=wait(&state);
  printf("Got child %d\n",p);
  }

and then whenever a child process dies, your main process will call catchchild.

As you've already worked out, if you have a count of how many children that have been forked, you could have catchchild update that so that your main code will know to fork a new child.

To answer your comment something like the following, except with more error checking

while(totalProcessesToBeForked)
  {
  if(currentChild < maxAllowedAtOnce)
    {
    forkChild(currentChild);
    totalProcessesToBeForked--;
    }
  sleep(1);
  }
Chris Turner
  • 8,082
  • 1
  • 14
  • 18
  • Please look at the updated code. I get the 'Got child', but most of the times it is after cleanup. – Ali Mar 29 '17 at 11:20
  • That is because your code is just starting the children and then doing the cleanup. There's no code in there to keep an eye on how many children are running and starting new ones as the old ones die. A `while` loop with a `sleep` in it would be a good place to start – Chris Turner Mar 29 '17 at 12:03
  • Where should I put the sleep, in the child? And what kind of while loop? – Ali Mar 29 '17 at 20:57
  • It does not fork any additional children, and appears to hang. I should have probably done this sooner, but here is a live example: http://ideone.com/noUs3m – Ali Mar 30 '17 at 22:21
  • @Ali ah! you didn't spot my comment after the code for `catchchild` that says "As you've already worked out, if you have a count of how many children that have been forked, you could have catchchild update that so that your main code will know to fork a new child." – Chris Turner Mar 31 '17 at 09:01
  • can you update the link code to show that? Would I set currentChild to numOfProcessesForkedSoFar, and then? B/c currentChild will always increment, right? – Ali Mar 31 '17 at 14:04
  • if currentChild isn't keeping track of how many children there are, just add a new variable that does and have that change as required – Chris Turner Mar 31 '17 at 14:12
  • I updated the while loop in the link. It seems to be working. Can you double check? Also, the logic would stay the same even if I am running another executable instead of printing out the date, correct? – Ali Mar 31 '17 at 14:19
  • Looks fine. Shouldn't matter what executable you're running. – Chris Turner Mar 31 '17 at 14:32
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/139600/discussion-between-ali-and-chris-turner). – Ali Mar 31 '17 at 14:33