printf() and fork() produce less output than expected
I'm learning about forking processes and memory management and I have come across this piece of code:
#include <stdio.h>
#include <libc.h>
int main() {
for (int i = 0; i < 3; ++i) {
printf("*");
fflush(stdout);
fork();
}
return 0;
}
By my calculations it should produce 7 stars: initial process prints a star (1 star), forks, now we have 2 processes, each of them prints a star (1 + 2 = 3), then they fork, so we have 4 processes, each of them prints a star and then dies as the program ends.
Thus, we should get 1 + 2 + 4 = 7 stars.
However, during some runs I get only 6 stars, like in the screenshot below:
Other times when I run the program everything is good and I get 7 stars as expected.
So far I have searched in the Internet and haven't found anything like that. Debugging also didn't help.
So, what can cause this strange behavior and how can I fix it?
When running this code from a terminal you will notice that your missing *
on some runs is not missing at all but printed after your program is finished.
For better understanding you might print the PID's instead of stars and an additional line when the process is about to finish:
int main() {
for (int i = 0; i < 3; ++i) {
printf("pid %d\n", getpid());
fflush(stdout);
fork();
}
printf ("pid %d terminates\n", getpid());
return 0;
}
The output on a run with missing print(s) will look something like this, indicating the terminal already returned before all processes have finished:
pid 31241
pid 31241
pid 31241
pid 31242
pid 31241 terminates
pid 31243
pid 31244 terminates
pid 31242
pid 31245
pid 31242 terminates
pid 31246 terminates
pid 31247 terminates
pid 31245 terminates
user@machine:~/bla$ pid 31243 terminates
pid 31248 terminates
To fix this you can let the parent process wait for its child processes before returning - this will cause your initial process to finish last and prevent the terminal from returning when there are still child processes running in the background:
while (wait(NULL) > 0);
printf ("pid %d terminates\n", getpid());
However, during some runs I get only 6 stars, ...
Other times when I run the program everything is good and I get 7 stars as expected.
You don't have control in which order the instances print the stars. One example of write()
(called implicitly by fflush()
), fork()
and the implicit exit()
at the end of the program could be:
instance 1: write() -> First star
instance 1: fork() -> New instance #2
instance 1: write() -> Second star
instance 2: write -> Third star
instance 2: fork() -> New instance #3
instance 1: fork() -> New instance #4
instance 1: write() -> Fourth star
instance 2: write() -> Fifth star
instance 2: exit()
instance 1: exit() -> Process #1 has finished
---- Process #1 does no longer exist ---
instance 3: write() -> Sixth star
instance 3: exit()
instance 4: write() -> Seventh star
instance 4: exit()
In the example, the sixth and the seventh star are printed, but AFTER the first process has finished.
However, the output of the program(s) is written to some "pipe" or "virtual terminal" and your text editor or IDE copies that output to the screen.
As soon as the "initial" process (instance #1) has finished, your IDE thinks that your program has finished and stops copying the data to the screen - so the sixth and the seventh star in the example are written by your program but they are not copied to the screen by the IDE.
each of them prints a star and then dies as the program ends.
... first, all 4 instances fork and then the 8 instances end.