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):
int_type
sputc(char_type __c)
{
int_type __ret;
if (__builtin_expect(this->pptr() < this->epptr(), true)) {
*this->pptr() = __c;
this->pbump(1);
__ret = traits_type::to_int_type(__c);
}
else
__ret = this->overflow(traits_type::to_int_type(__c));
return __ret;
}
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.
printf
shines as the complete output is written tostdout
in one shot; when usingstd::cout
each link of the expression chain would be output separately tostdout
; in between them there can be some other thread writing tostdout
due to which the final output's order gets messed up. – Experimentation