I was looking at some simple code on fork, and decided to try it out for myself. I compiled and then ran it from inside Emacs, and got a different output to that output produced from running it in Bash.
#include <unistd.h>
#include <stdio.h>
int main() {
if (fork() != 0) {
printf("%d: X\n", getpid());
}
if (fork() != 0) {
printf("%d: Y\n", getpid());
}
printf("%d: Z\n", getpid());
}
I compiled it with gcc, and then ran a.out from inside Emacs, as well as piping it to cat
, and grep .
, and got this.
2055: X
2055: Y
2055: Z
2055: X
2058: Z
2057: Y
2057: Z
2059: Z
This isn't right. Running it just from Bash I get (which I expected)
2084: X
2084: Y
2084: Z
2085: Y
2085: Z
2087: Z
2086: Z
edit - missed some newlines
What's going on?
The order in which different processes write their output is entirely unpredictable. So the only surprise is that sometimes the "X" print statement sometimes happens twice.
I believe this is because sometimes at the second fork()
, an output line including "X" is in an output buffer, needing to be flushed. So both processes eventually print it. Since getpid()
was already called and converted into the string, they'll show the same pid.
I was able to reproduce multiple "X" lines, but if I add fflush(stdout);
just before the second fork()
, I always only see one "X" line and always a total of 7 lines.
I think I know what's going on. The stdio buffering will be different when output is a tty versus when it's a pipe or a file. The child processes inherit the parent buffers. When they're flushed, you can get double output.
If you add
fflush(stdout);
right after each printf()
call, you'll see what I mean.
The interesting thing is that it's different when standard output is a tty device. It may be that the library knows what that means, and flushes after each line break, or something like that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With