1

I'm trying to write a program that has a single parent process create multiple children in a while loop. For testing I started trying to make only 4 processes (1 parent and its 3 children). But it seems like the children are executing code above the line they were created in, even though there is no recursion (to my knowledge) for them to go back to that line.

Here's what I have right now:

int main() {

  time_t start;
  time_t end;
  int i = 0;
  pid_t pid;

  start = time(NULL);
  printf("Αρχική τιμή δευτερολέπτων %d\n", start);

  pid = fork();
  printf("%d ", pid);
  while (i < 2) {
    if (pid > 0) {
      fork();
      wait();
      i++;
    }
  }

  printf("check ");

  printf("%d", pid);

  if (pid > 0) {
    end = time(NULL);
    printf("%d\n", end - start);
  }

  return 0;
}

My output for that is:

Αρχική τιμή δευτερολέπτων 1547394155
29338 check 29338 0
29338 check 29338 0
29338 check 29338 0
29338 check 29338 0

So it seems like printf ("%d ", pid) is running 4 times, even though there should only be 2 processes running at the time.

Kusalananda
  • 320,670
  • 36
  • 633
  • 936
Oathkeeper594
  • 13
  • 1
  • 3
  • `wait()` typically requires an argument. otherwise, try adding `sleep(9999)` or similar and then using `pstree` or something to inspect how the processes are laid out; the fork/wait/while code is very suspect, and printing from both the parent and children processes may run into buffering issues. – thrig Jan 13 '19 at 16:36
  • regarding: `pid = fork();` and `fork()` the function has three different types of returned values. 1) <0 means an error occurred 2) ==0 means the child process is running 3) > 0 means the parent is running. The code should be checking/handling all three conditions – user3629249 Jan 13 '19 at 22:19
  • when asking a question about a runtime problem, as this question is doing, post a [mcve] so we can reproduce the problem and help you to debug it. – user3629249 Jan 13 '19 at 22:21
  • regarding: `pid = fork(); printf("%d ", pid);` all three conditions from the call to `fork()` will be executing that `printf()` statement (hopefully the error condition is not asserted) so the `printf()` statement will be executed twice. Regarding: `fork(); wait();` all three conditions will be executing the `wait()`, However, only the parent should be executing the `wait()`. The code really needs to be checking the returned values from the C library functions: `wait()` and `fork()` – user3629249 Jan 13 '19 at 22:27
  • BTW: this statement: `wait();` will cause a compile problem, because the syntax is: `pid_t wait( int *status )` and `(int *status)` is not the same as `()` – user3629249 Jan 13 '19 at 22:31

2 Answers2

1

This is similar to the issue in "Why does a program with fork() sometimes print its output multiple times?".

The output buffer is not flushed immediately when you do printf("%d ", pid) since the string is not terminated by a newline, and since you don't call fflush(stdout). This means that the unflushed buffer is inherited by the child processes and you get original parent's PID outputted too many times when the buffer finally is flushed by the last printf() call (which outputs a newline) or at the end of the program's execution.

Inserting fflush(stdout) directly after that printf() call (along with including the appropriate headers and calling wait() correctly) will result in something like

Αρχική τιμή δευτερολέπτων 1547400480
79301 0 check 793010
check 793010
check 793010
check 793010

Also note that you will get a process that is indefinitely looping in the while loop (the first child process, whose pid value is zero).

Kusalananda
  • 320,670
  • 36
  • 633
  • 936
  • Well I think this is not the problem, I tried that one please see it:https://ideone.com/SDOGlt – Prvt_Yadav Jan 13 '19 at 17:03
  • @P_Yadav With your C++ code, I only get two copies of the `1` line output, as expected. – Kusalananda Jan 13 '19 at 17:16
  • Got it, but can you please one more time look at the link I think output `3 0` should be three times instead of 4 times because first child will get `pid` value=0, then how can it execute last `printf` statement of the code? – Prvt_Yadav Jan 13 '19 at 17:37
  • No, it's not that in this case; the ` printf("%d", pid);` will be actually called 4 times ;-) –  Jan 13 '19 at 17:41
  • @mosvy thanks for response but I am not talking about that one, last one means inside the if condition `printf("%d\n", end - start);`. I am getting this if condition called 4 times. – Prvt_Yadav Jan 13 '19 at 17:44
  • @P_Yadav That's from each of the additional child processes created in the `while` loop. Their `pid` value will be greater than zero as it's inherited from their parent and not reset. – Kusalananda Jan 13 '19 at 19:47
0

First of all, notice that calling wait() without an argument is not acceptable; it's not the same as wait(NULL); it will either fail with EFAULT or trash memory around when trying to store the status.

I'll try to explain what happens in your code, without running it (I've had my share of fork bombs, thank you very much).

  pid = fork();
  printf("%d ", pid);
  while (i < 2) {
    if (pid > 0) {
      fork();
      wait();
      i++;
    }
  }

After the first fork, you will have 2 processes; pid will be equal to 0 in the child, so the child will continue to run in an infinite loop, because the i++ will be executed only when pid > 0.

From that point on, pid > 0 will be true in the parent and all the children created by the 2nd fork from inside the loop, because the pid variable is never updated again anywhere.

So the fork() from inside the loop will create (1) a child on the first run in the parent, (2) a child on the second run in the parent and (3) yet another child on the second run in the child created in the first run of the loop.

That makes 3 + 1 = 4 processes, which will all run through the end of the main() function, and pid > 0 will be true in all of them, so they will all print out the whole stuff (including the unflushed data added by the printf("%d ", ... just before the while loop).


As a sidenote, you should use dprintf(1 or 2, ...) anytime you want a debugging printf(); that will get any spurious buffering (and spurious fears about it happening) out of the way; dprintf() is now also part of the standard.