Is writing to stdout using printf
thread-safe on Linux? What about using the lower-level write
command?
相关问题
- Multiple sockets for clients to connect to
- Is shmid returned by shmget() unique across proces
- What is the best way to do a search in a large fil
- glDrawElements only draws half a quad
- how to get running process information in java?
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 withFILE*
objects are thread-safe. The ones that aren't usually haveunlocked
in their names (e.g.getc_unlocked(3)
). However, the thread safety is at a per-function call level: if you make multiple calls toprintf(3)
, for example, each of those calls is guaranteed to output atomically, but other threads might print things out between your calls toprintf()
. If you want to ensure that a sequence of I/O calls gets output atomically, you can surround them with a pair offlockfile(3)/funlockfile(3)
calls to lock theFILE
handle. Note that these functions are reentrant, so you can safely callprintf()
in between them, and that won't result in deadlock even thoughtprintf()
itself makes a call toflockfile()
.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 thesysenter
instruction, or theint
(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.They are both thread-safe to the point that your application won't crash if multiple threads call them on the same file descriptor. However, without some application-level locking, whatever is written could be interleaved.
C got a new standard since this question was asked (and last answered).
C11 now comes with multithreading support and addresses multithreaded behavior of streams:
So, an implementation with C11 threads must guarantee that using
printf
is thread-safe.Whether atomicity (as in no interleaving1) is guaranteed, wasn't that clear to me at a first glance, because the standard spoke of restricting interleaving, as opposed to preventing, which it mandated for data races.
I lean towards it being guaranteed. The standard speaks of restricting interleaving, as some interleaving that doesn't change the outcome is still allowed to happen; e.g.
fwrite
some bytes,fseek
back some more andfwrite
till the original offset, so that bothfwrite
s are back-to-back. The implementation is free to reorder these 2fwrite
s and merge them into a single write.1: See the strike-through text in R..'s answer for an example.
It's thread-safe; printf should be reentrant, and you won't cause any strangeness or corruption in your program.
You can't guarantee that your output from one thread won't start half way through the output from another thread. If you care about that you need to develop your own locked output code to prevent multiple access.
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 theFILE
object states, etc. if you useprintf
simultaneously from multiple threads.However, allstdio
operations are formally specified in terms of repeated calls tofgetc
andfputc
, 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 forflockfile
: http://pubs.opengroup.org/onlinepubs/9699919799/functions/flockfile.htmlYou can use the
flockfile
,ftrylockfile
, andfunlockfile
functions yourself to achieve larger-than-single-function-call atomic writes.