Short answer: don't mix buffered and unbuffered code.
Long answer: let's test variants of your source code using the following commands:
$ rm dump
$ for X in 0 1 2 3 4 5 6 7 8 9; do for Y in 0 1 2 3 4 5 6 7 8 9; do for Z in 0 1 2 3 4 5 6 7 8 9; do echo `./program` >> dump; done; done; done
$ sort -u dump
This executes program
a thousand times, and lists all unique outputs it returned.
Buffered version: replace write
by fwrite
(or printf
)
#include <unistd.h>
#include <stdio.h>
int main()
{
fork();
printf("b");
if (fork() == 0) {
fwrite("a", 1, 1, stdout);
}else{
fwrite("c", 1, 1, stdout);
}
return 0;
}
This gives a very regular pattern of output. In fact, only six outputs are possible:
bababcbc
babcbabc
babcbcba
bcbababc
bcbabcba
bcbcbaba
What is going on?
- After the first fork, there are two processes, W and Y.
- Both processes write a letter
"b"
to the stdout
stream. The stream is buffered by default, so .
- After second fork, there are four processes: W and X, Y and Z. The
stdout
streams of W and X have the same state, so also the same buffer containing just "b"
. The same holds for Y and Z.
- All four processes write another letter to the
stdout
stream.
- After
main
returns, the C runtime takes over. Every process flushes their buffers, including the buffers of stdout
.
Unbuffered version: replace printf
by write
#include <unistd.h>
int main()
{
fork();
write(1, "b", 1);
if (fork() == 0) {
write(1, "a", 1);
}else{
write(1, "c", 1);
}
return 0;
}
The possible output is now a little more varied, but it's still pretty understandable, given concurrency:
bbacca
bbcaac
bbcaca
bbccaa
bcabca
bcbaca
This is probably the output you expected.
Mixed version (yours)
Your code gives many more results than the previous two variants:
cabbacbb
cabbcabb
cabbcbab
cabcabbb
cabcbabb
cabcbbab
... etc ...
This is because the write
call will produce output immediately, but the buffered "b"
will only be printed when each process terminates, which is after the write
call, of course. Just like in the fully buffered version, every process will have that "b"
in the stdout
buffer, so you'll end up seeing four of them.