Hello,
I have some issues (i.e. crashes) with TString in a multi-threaded environment.
Attached is a multi-threaded example using TStrings.
My work flow is the following:
I create a set of strings in the main thread.
I make copies of those strings in the worker threads and do something with them.
Executing this example will always results in a crash…
However, this is only related to TString. The moment I replace TString with std::string everything is fine (uncomment the line #define TString string in the attached example).
I did some debugging with valgrind’s helgrind and the reasons seems to be that TString doesn’t make a clean copy of the data, but keeps references/pointers to the original data. And this is of course fatal across thread boundaries…
Example helgrind output:
valgrind --tool=helgrind -v --error-limit=no CrashTest
==7240== Possible data race during read of size 4 at 0x90f51bc by thread #3
==7240==    at 0x49F2DBC: TRefCnt::RemoveReference() (TRefCnt.h:43)
==7240==    by 0x4A0D154: TStringRef::UnLink() (TString.h:441)
==7240==    by 0x4A0874C: TString::~TString() (TString.cxx:396)
==7240==    by 0x804B276: CrashTest::DoLoopB() (CrashTest.cxx:171)
==7240==    by 0x804B318: StartThreadB(void*) (CrashTest.cxx:206)
==7240==    by 0x6B0DC05: TThread::Function(void*) (TThread.cxx:696)
==7240==    by 0x402961F: mythread_wrapper (hg_intercepts.c:202)
==7240==    by 0x72BD96D: start_thread (pthread_create.c:300)
==7240==    by 0x798DA4D: clone (clone.S:130)
==7240==  This conflicts with a previous write of size 4 by thread #2
==7240==    at 0x804B5EF: TRefCnt::AddReference() (TRefCnt.h:42)
==7240==    by 0x804B640: TString::TString(TString const&) (TString.h:226)
==7240==    by 0x804BA71: __gnu_cxx::new_allocator::construct(TString*, TString const&) (new_allocator.h:105)
==7240==    by 0x804B8F7: std::vector<TString, std::allocator >::push_back(TString const&) (stl_vector.h:737)
==7240==    by 0x804AFF9: CrashTest::DoLoopA() (CrashTest.cxx:144)
==7240==    by 0x804B2F0: StartThreadA(void*) (CrashTest.cxx:198)
==7240==    by 0x6B0DC05: TThread::Function(void*) (TThread.cxx:696)
==7240==    by 0x402961F: mythread_wrapper (hg_intercepts.c:202)
So… is it intended that one cannot use TString’s across thread boundaries, because TString is simply not thread safe. In this case I probably have to come up with my own string class…
But I have my doubts that this can be intended, because TString is so deeply integrated into ROOT that one will always come across a situation like the one in the example when one uses ROOT in a multi-threaded environment?
Any advice is appreciated.
Thanks,
Andreas
CrashTest.cxx (5.56 KB)