Search code examples
clinuxforkexecfopen

c - Why no race condition with fopen / fprintf


I am trying to simulate a race condition (is this a correct term?) in order to fix it with semaphores afterward.

I have a master.c process:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int main()
{
    for(int i = 0; i < 100; ++i)
    {
        if (fork() == 0)
        {
            char str[12];
            sprintf(str, "%d", i%10);
            execl("./slave", "slave", str, (char *)0);
        }
    }

    return 0;
}

And a slave.c process which prints into a file:

#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    FILE *p_file;
    p_file = fopen("out.txt", "a");
    for (int i = 0; i < 100; ++i)
    {
        usleep(100000); // I tried using this but it changes nothing
        fprintf(p_file, "%s", argv[1]);
    }
    fprintf(p_file, "\n");

    return 0;
}

The output file out.txt looks like this: https://pastebin.com/nU6YsRsp

The order is "random", but no data is not corrupted for some reason. Why is that?


Solution

  • Because stdio uses buffered output by default when writing to a file, and everything you're printing in each process fits into a single buffer. The buffer doesn't get flushed until the process exits, and then it's written as a single write() call, which is small enough to be written atomically to the file.

    Call fflush(p_file); after each fprintf() and you'll get more mixed up results. Or call setvbuf() to disable buffering.