3

please look at following code.

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(void)
{

        fork();
        printf(".");
        fflush(stdout);
        fork();
        printf(",");

   return 0;
}

the output is :

..,,,,

this is ok for me,

but if I remove fflush(stdout) from the above program then the output should be(as per my understanding).

  ...,.,.,.,

the statement of fork() is : the statements immediately after fork() are copied into both parent and child.

what I understand is : after the first fork() there are two process (assume it as process p and process c) we have

the code in process p and c is :

    printf(".");
    fork();
    printf(",");

now , suppose the first statement of process p and c is executed , so the output will be .

  ..

now the fork() statement comes to execute . so , after executing fork() , our processes are like p , pc ,c ,cc.

the code in each of p , pc , c and cc is

    printf(",");

we do not flush the stdout so printf(".") is still there in each of the buffer .

so each process will print ., so the output is

 .,.,.,.,

my question is : 1) where is previous .. ? i.e. as per my explanation the output should be

                ...,.,.,.,
Michael Foukarakis
  • 39,737
  • 6
  • 87
  • 123
user2742399
  • 61
  • 2
  • 6
  • 1
    So you expect `.` to be already printed, yet at the same time still be in the buffer? Or am I misunderstanding your expectations? –  Sep 07 '13 at 08:49
  • 1
    You should *always* keep the `pid_t` *result* of [fork(2)](http://man7.org/linux/man-pages/man2/fork.2.html) and you should handle the three cases: failure (result is -1), success in parent (result is a positive pid of the child) , success in child (result is 0). – Basile Starynkevitch Sep 07 '13 at 08:51
  • Read a good book like [Advanced Linux Programming](http://advancedlinuxprogramming.com/) -which has a full chapter about processes- and the wikipage on [fork system call](http://en.wikipedia.org/wiki/Fork_%28system_call%29) – Basile Starynkevitch Sep 07 '13 at 08:53
  • @hvd : yes , `.` should be printed at the terminal , and as I don't flush the `stdout` , it should be still be in the buffer (as per my understanding). – user2742399 Sep 07 '13 at 08:53
  • @user2742399 But it doesn't get printed until the buffer is flushed. So the `.`s and `,`s are *either* already printed out *or* still in the buffer. Your scenario requires both of these to be true at the same time. – Magnus Hoff Sep 07 '13 at 08:55
  • @user2742399 That's not how buffered output works. The buffer contains the things that haven't yet been printed. If you make sure there's a pause right after `printf`, you'll see that the `.` is not on the screen. It doesn't get on the screen until the buffer is flushed. –  Sep 07 '13 at 08:56
  • 1
    Without any locking or synchronization, the order of output between the four processes is not completely deterministic. While the scheduler will usually play fair, you have very little control over what it does and other system events that could influence it. For example, other processes running at varying priorities. It's unwise to assume anything about the output order across these different forked processes. – selbie Sep 07 '13 at 08:56
  • change `printf(".\n");` – Grijesh Chauhan Sep 07 '13 at 09:08
  • A similar post here:http://theunixshell.blogspot.in/2013/07/fork-system-call-and-duplicating-buffer.html – Vijay Apr 22 '14 at 10:19

2 Answers2

5

Since there's no flush, nothing will be written. Each of the forked processes will have ".," ready to write after the second printf.

    fork();

We have two processes.

    printf(".");

Each of them is ready to write ".".

    fork();

We have four processes.

    printf(",");

Each of them is now ready to write ".,".

    return 0;

As each process flushes, it writes ".," to stdout, producing the most likely output ".,.,.,.,".

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
4

Without flushing, every process (total 4 after 2 forks) will buffer it's output, and print it (by exit handler installed by library, I think) when process exits, because all output here fits in buffers and you do not trigger flushing them. So each process will print exactly ., as one write to the kernel. You have no synchronization between processes (such as parent waiting for child exit before exiting itself), so order is undefined, up to the whims of kernel process scheduler, but since output each process is same, it does not matter to what is output:

.,.,.,.,

So the crucial thing here is, with question code, without flushing, writes happen in blocks of 2 chars, with no possibility of interleaving of individual chars. But this depends on console implementation of course, and one could write a console driver which always worked one char at a time, and then interleaving of individual chars could happen. I'm saying this to clarify, that what you see is not some standard well defined behavior, it's just how things happen to work because of implementation details.

hyde
  • 60,639
  • 21
  • 115
  • 176