dimanche 28 novembre 2021

Thread safety of std::cout insertion operator

I've always thought that using std::cout << something was thread safe.

For this little example

#include <iostream>
#include <thread>

void f()
{
   std::cout << "Hello from f\n";
}

void g()
{
   std::cout << "Hello from g\n";
}

int main()
{
   std::thread t1(f);
   std::thread t2(g);
   t1.join();
   t2.join();
}

my expectation was that the order of the two outputs would be undefined (and indeed that is what I observe in practice), but that the calls to operator<< are thread safe.

However, ThreadSanitizer, DRD and Helgrind all seem to give various errors regarding access to std::__1::ios_base::width(long) and std::__1::basic_ios<char, std::__1::char_traits >::fill()

On Compiler Explorer I don't see any errors.

On FreeBSD 13, ThreadSanitizer gives me 3 warnings, the two listed above plus the malloc/memcpy to the underlying i/o buffer.

Again in FreeBSD 13, DRD gives 4 errors, width() and fill() times two for the two threads.

Finally FreeBSD 13 Helgrind gives one known false positive related to TLS in thread creation, fill()and ẁidth()` twice.

On Fedora 34

  • No errors with g++ 11.2.1 and ThreadSanitizer
  • DRD complains about malloc/memcpy in fwrite with g++ compiled exe
  • Helgrind also complains about fwrite and also for the construction of cout, again with the g++ compiled exe
  • clang++ 12 ThreadSanitizer complains about fill() and width()
  • DRD with the clang++ compiler exe complains about fill(), width(), fwrite and one other in start_thread
  • Helgrind with the clang++ exe complains about some TLS, fill(), width(), fwrite

Looking at the libc++ and libstdc++ code I don't see anything at all that protects width(). So I don't understand why there are no complaints on compiler explorer.

Is there a way with tsan to either see the suppresions that are being used or to ignore default suppressions (assuming that there are some default suppressions)?

Aucun commentaire:

Enregistrer un commentaire