In general I assume that streams are not synchronized, it is up to the user to do appropriate locking. However, do things like cout
get special treatment in the standard library?
That is, if multiple threads are writing to cout
can they corrupt the cout
object? I understand that even if synchronized you'd still get randomly interleaved output, but is that interleaving guaranteed. That is, is it safe to use cout
from multiple threads?
Is this vendor dependent? What does gcc do?
Important: Please provide some kind of reference for your answer if you say "yes" since I need some kind of proof of this.
My concern is also not about the underlying system calls, those are fine, but the streams add a layer of buffering on top.
This is a great question.
First, C++98/C++03 has no concept of "thread". So in that world, the question is meaningless.
What about C++0x? See Martinho's answer (which I admit surprised me).
How about specific implementations pre-C++0x? Well, for example, here is the source code for
basic_streambuf<...>:sputc
from GCC 4.5.2 ("streambuf" header):Clearly, this performs no locking. And neither does
xsputn
. And this is definitely the type of streambuf that cout uses.As far as I can tell, libstdc++ performs no locking around any of the stream operations. And I would not expect any, as that would be slow.
So with this implementation, obviously it is possible for two threads' output to corrupt each other (not just interleave).
Could this code corrupt the data structure itself? The answer depends on the possible interactions of these functions; e.g., what happens if one thread tries to flush the buffer while another tries to call
xsputn
or whatever. It might depend on how your compiler and CPU decide to reorder memory loads and stores; it would take a careful analysis to be sure. It also depends what your CPU does if two threads try to modify the same location concurrently.In other words, even if it happens to work fine in your current environment, it might break when you update any of your runtime, compiler, or CPU.
Executive summary: "I wouldn't". Build a logging class that does proper locking, or move to C++0x.
As a weak alternative, you could set cout to unbuffered. It is likely (although not guaranteed) that would skip all logic related to the buffer and call
write
directly. Although that might be prohibitively slow.The C++03 standard does not say anything about it. When you have no guarantees about the thread-safety of something, you should treat it as not thread-safe.
Of particular interest here is the fact that
cout
is buffered. Even if the calls towrite
(or whatever it is that accomplishes that effect in that particular implementation) are guaranteed to be mutually exclusive, the buffer might be shared by the different threads. This will quickly lead to corruption of the internal state of the stream.And even if access to the buffer is guaranteed to be thread-safe, what do you think will happen in this code?
You probably want each line here to act in mutual exclusion. But how can an implementation guarantee that?
In C++11, we do have some guarantees. The FDIS says the following in §27.4.1 [iostream.objects.overview]:
So, you won't get corrupted streams, but you still need to synchronize them manually if you don't want the output to be garbage.
www.techrepublic.com/article/use-stl-streams-for-easy-c-plus-plus-thread-safe-logging
and also: Are standard output streams in C++ thread-safe (cout, cerr, clog)?
UPDATE
Please have a look at @Martinho Fernandes' answer to know about what the new standard C++11 tells about this.
As other answers mention, this is definitely vendor-specific since the C++ standard makes no mention of threading (this changes in C++0x).
GCC doesn't make a whole lot of promises about thread safety and I/O. But the documentation for what it does promise is here:
the key stuff is probably:
I don't know if anything has changed sine the 3.0 timeframe mentioned.
MSVC's thread safety documentation for
iostreams
can be found here: http://msdn.microsoft.com/en-us/library/c9ceah3b.aspx:Note that that information is for the most recent version of MSVC (currently for VS 2010/MSVC 10/
cl.exe
16.x). You can select the information for older versions of MSVC using a dropdown control on the page (and the information is different for older versions).