stdout thread-safe in C on Linux?
It's not specified by the C standard -- it depends on your implementation of the C standard library. In fact, the C standard doesn't even mention threads at all, since certain systems (e.g. embedded systems) don't have multithreading.
In the GNU implementation (glibc
), most of the higher-level functions in stdio that deal with FILE*
objects are thread-safe. The ones that aren't usually have unlocked
in their names (e.g. getc_unlocked(3)
). However, the thread safety is at a per-function call level: if you make multiple calls to printf(3)
, for example, each of those calls is guaranteed to output atomically, but other threads might print things out between your calls to printf()
. If you want to ensure that a sequence of I/O calls gets output atomically, you can surround them with a pair of flockfile(3)/funlockfile(3)
calls to lock the FILE
handle. Note that these functions are reentrant, so you can safely call printf()
in between them, and that won't result in deadlock even thought printf()
itself makes a call to flockfile()
.
The low-level I/O calls such as write(2)
should be thread-safe, but I'm not 100% sure of that - write()
makes a system call into the kernel to perform I/O. How exactly this happens depends on what kernel you're using. It might be the sysenter
instruction, or the int
(interrupt) instruction on older systems. Once inside the kernel, it's up to the kernel to make sure that the I/O is thread-safe. In a test I just did with the Darwin Kernel Version 8.11.1, write(2)
appears to be thread-safe.
Whether you'd call it "thread-safe" depends on your definition of thread-safe. POSIX requires stdio
functions to use locking, so your program will not crash, corrupt the FILE
object states, etc. if you use printf
simultaneously from multiple threads. However, all stdio
operations are formally specified in terms of repeated calls to fgetc
and fputc
, so there is no larger-scale atomicity guaranteed. That is to say, if threads 1 and 2 try to print "Hello\n"
and "Goodbye\n"
at the same time, there's no guarantee that the output will be either "Hello\nGoodbye\n"
or "Goodbye\nHello\n"
. It could just as well be "HGelolodboy\ne\n"
. In practice, most implementations will acquire a single lock for the entire higher-level write call simply because it's more efficient, but your program should not assume so. There may be corner cases where this is not done; for instance an implementation could probably entirely omit locking on unbuffered streams.
Edit: The above text about atomicity is incorrect. POSIX guarantees all stdio
operations are atomic, but the guarantee is hidden in the documentation for flockfile
: http://pubs.opengroup.org/onlinepubs/9699919799/functions/flockfile.html
All functions that reference ( FILE *) objects shall behave as if they use flockfile() and funlockfile() internally to obtain ownership of these ( FILE *) objects.
You can use the flockfile
, ftrylockfile
, and funlockfile
functions yourself to achieve larger-than-single-function-call atomic writes.