Ubarjohade
Ubarjohade

Reputation: 471

Forking within C - infinite loop?

Attempting to learn C forking. It correctly prints the number of times the main loop is suppose to run and the right number of threads but the execution time is off and the program never terminates. Am I making an infinite amount of processes?

After some suggestions here is a cleaner version of the code. The old version is located below. The updated part is still creating to many child processes and never exiting. I'm just not seeing what's going wrong.

Update: Suggestion by John Hascall fixed a formatting and threads running out of order. An infinite number of threads are still generated but now in the correct order. I.e prints thread execution time 1, 2, 3, 4... etc. Don't think the problem is the wait syscall but going to study it and see if I can't find anything.

Update**: I found the solution. The first problem I believe was that I didn't have a wait command and the second is that when putting in the wait I accidentally removed the check for count < argv[1]. I put it back in and it seems to be running correctly! Thanks for the help and style pointers everyone! Working version is below.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "./processes.h"

int main(int argc, char** argv) {
  if (argc != 4) {
    printf("Wrong number of arguments entered. Usage: #processes sleepTime inputFile.\n");
    return 1;
  }

  if(atoi(argv[1]) <= 0){
    printf("Incorrect number of children, must be greater than 0");
    return -1;
  }

  int count = 0;
  int index;
  Child *child = malloc(sizeof(Child) * atoi(argv[1]));
  int childIndex;
  int pid;

  do{
    switch (pid = fork()){
      case -1:
        printf("Fork failed\n");
        exit(1);

      case 0:
        sleep(atoi(argv[2]) * childIndex);
        gettimeofday(&child[childIndex].endTime, NULL);
        double elapsed = child[childIndex].endTime.tv_usec - child[childIndex].startTime.tv_usec;
        printf("Time for process %d = %f microseconds\n", childIndex, elapsed);
        break;

     default: 
        childIndex = count + 1;
        gettimeofday(&child[count].startTime, NULL);
        child[count].index = count + 1;
        child[count].pid = pid;
        count++;
    }
  } while((wait(NULL) != -1) && (count < atoi(argv[1])));

  return 1;
}

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "./processes.h"

int main(int argc, char** argv) {
  if (argc != 4) {
    printf("Wrong number of arguments entered. Try again.");
    return 1;
  }

  if(atoi(argv[1]) <= 0){
    printf("Incorrect number of children, must be greater than 0");
    return -1;
  }

  int count;
  int index;
  Child *child = malloc(sizeof(Child) * atoi(argv[1]));
  int pid = 1;
  int childIndex;

  for (count = 0; count < atoi(argv[1]); count++) {
    if (pid != 0) {
      childIndex = count + 1;
      gettimeofday(&child[count].startTime, NULL);
      child[count].index = count + 1;
      pid = fork();

      if (pid != 0){
        child[count].pid = pid;
        printf("Main thread loop: %d\n", count);
        printf("Child process: %d\n", getpid());
      } 
    }
  }

  if (pid == 0) {
    //this is the child process
    sleep(atoi(argv[2]) * childIndex);
    gettimeofday(&child[childIndex].endTime, NULL);
    double elapsed = child[childIndex].endTime.tv_usec - child[childIndex].startTime.tv_usec;
    printf("Time for process %d = %f microseconds\n", childIndex, elapsed);

    //printf("This is thread %d reporting in.\n", childIndex);
  }

//  printf("Testing\n");
return 1;
}

Upvotes: 4

Views: 2969

Answers (1)

John Hascall
John Hascall

Reputation: 9416

The bigest issue is your child's code:

if (pid == 0) {
    ....
}

belongs in the same loop (say right after) the parent's code:

if (pid != 0) {
    ....
}

Also, you never check for pid == -1 (the fork() failed).

A more standard way to write something like this is:

switch (pid = fork()) {
    case -1:
         /* handle fork error */
         exit(1);
    case 0:
         /* child code goes here */
         _exit(0);
    default:
         /* parent code goes here */
}
/* Also you probably want to look into the `wait()` syscall. */
do {} while (wait(NULL) != -1);       /* <--- the very minimum */

Upvotes: 5

Related Questions