2

can you tell me, why is output of this program this: 1 2 2 5 5 3 4 5 4 5 3 4 5 4 5

And quick explanation why is that like this? Thanks

main()
{
    printf("1\n");
    fork();
    printf("2\n");
    if(fork()==0)
    {
        printf("3\n");
        fork();
        printf("4\n");
    }
    printf("5\n");
}
Michael
  • 199
  • 2
  • 16
  • 6
    Actually this output is not always the same – Deck Dec 05 '13 at 18:47
  • printf is not thread secure, so, may be when printf is trying to output something to the stdout, it's blocked and it doesn't get printed. You'd have to try thread-safe functions, like cout in C++. – fernando.reyes Dec 05 '13 at 18:50
  • 2
    @fernando.reyes The question is about forked processes, thread-safe doesn't make a (relevant) difference here. – johannes Dec 05 '13 at 18:51
  • Read this http://stackoverflow.com/questions/16262165/why-possible-of-if-and-else-statement-executed-on-single-run/16262206#16262206 – Bartosz Marcinkowski Dec 05 '13 at 18:52
  • @fernando.reyes POSIX does make some thread safety guarantees for `printf`. In this case, though, serialization is between *processes*, via atomicity of `write` for fewer-than-`PIPE_BUF` characters. – zwol Dec 05 '13 at 18:54
  • 2
    it is a good practice to always `fflush(stdout)` and `fflush(stderr)` before a `fork`, this prevents buffered data to output twice – alexgirao Dec 05 '13 at 19:59
  • 1
    @alexgirao good point (the OP is relying on auto-line-buffering of terminal output in most Unix C libraries). I've added some stuff to my answer about that. – zwol Dec 05 '13 at 20:23

7 Answers7

13

The output of your program, assuming no calls to fork fail, should be thought of like this:

1
2     2
  3     3
  4 4   4 4
5 5 5 5 5 5

Each column represents the output of one process. They all get serialized onto stdout in some random order, subject only to the following constraints: within a column, each character cannot appear before the character immediately above it; the topmost character in each column cannot appear before the character above and to the left of it.

Note that right now your program is relying on the C library noticing that stdout is a terminal and therefore setting it to line-buffered. If you run the program with stdout redirected to a file or pipe you are likely to get rather different output, e.g.

$ ./a.out | tr '\n' ' '
1 2 5 1 2 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5

... because in that case all of the output is buffered until returning from main, and the buffers are copied into each child process. Adding

setvbuf(stdout, 0, _IONBF, 0);

before the first printf statement will prevent duplication of output. (In this case you could get away with _IOLBF instead, but _IONBF is safer for code like this.)

zwol
  • 135,547
  • 38
  • 252
  • 361
4

It would be a little easier to show graphically, but everytime you call fork() you have another process continue through the same code. So:

Process 1 (original process): prints 1, then creates Process 2, prints 2, then creates Process 3 but doesn't return 0, and prints 5.

Process 2: prints 2, then creates Process 4 but doesn't return 0, and prints 5.

Process 3: prints 3, then creates Process 5, prints 4, prints 5

Process 4: prints 3, then creates Process 6, prints 4, prints 5

Process 5: prints 4, prints 5

Process 6: prints 4, prints 5

But they are all happening in similar time so that why you get all those numbers.

Hope that helps. First time answering!

Snowman6286
  • 150
  • 6
3

See in some flavor suppose in fedora parent get chance first to execute and then child but in other like ubuntu child get first preference on the basis of that you will see the out put. No relation with printf function in this scope but we can predict how many times the body of the method will execute here I am attaching one image may it is helpful for you. enter image description here

Here when 1 print only one process. After execution of first fork then two different process each is having fork but inside your if statement. So one again creates two process but only one will get the chance to enter in the if body. Again fork will execute and again new process will generates. The formula is total number of process=2*n. Where n is the number of fork() method inside your function. So total six methods will have some condition to printing any number like 2,3,4 but 5 is common to all so 5 will print six times. May be my post helpful for you Thanks asif aftab

asifaftab87
  • 1,315
  • 24
  • 28
1

Its since you're not always testing for the fork() calls result. The zero result path will remain the parent process and the else part will be executed as child process. As you're not testing that every code following a fork(); call will be duplicated (and executed) in both processes.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
0

the output is not deterministic due to the order of execution and inheritance of the output buffers, a way to be deterministic is with

#include <stdlib.h>
#include <stdio.h>

main()
{
  printf("1\n");
  fflush(stdout);
  if (fork()) wait(0);
  printf("2\n");
  fflush(stdout);
  if(fork()==0)
    {
      printf("3\n");
      fflush(stdout);
      if (fork()) wait(0);
      printf("4\n");
    } else wait();
  printf("5\n");
}
alexgirao
  • 885
  • 9
  • 9
0

Using fork() we create a child process, and there is no execution pattern gurantee for either parent or child, as discussed here.

If you want to have an execution pattern, its better to put a check on fork() for the parent [pid is not 0] or child [pid is 0] and make either of them to sleep so that scheduler puts the other one on execution.

You can find more information here.

Community
  • 1
  • 1
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
-2

Micheal, I would need to see the code inside of the fork() method to know for sure, but being that it is printing numbers extra numbers, the only possible explanation that I can think of is that your fork() method might have print methods of its own.

Robin

  • 2
    See http://linux.die.net/man/2/fork for details on `fork`. - It creates a child process that continues execution just after the fork statement. – Bill Dec 05 '13 at 18:57