Search code examples
cprocessfork

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:

enter image description here

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?


Solution

  • 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());