Given that:
1) The C++03 standard does not address the existence of threads in any way
2) The C++03 standard leaves it up to implementations to decide whethe
A more correct way to look at it would be "You cannot safely and portably use C++ in a multithreaded environment". There is no guarantee that other data structures will behave sensibly either. Or that the runtime won't blow up your computer. The standard doesn't guarantee anything about threads.
So to do anything with threads in C++, you have to rely on implementation-defined guarantees. And Then you can safely use std::string because each implementation tells you whether or not it is safe to use in a threaded environment.
You lost all hope of true portability the moment you spawned a second thread. std::string isn't "less portable" than the rest of the language/library.