Re: How to create a volatile std::string?
On Feb 1, 1:42 am, Sam <s...@email-scan.com> wrote:
Juha Nieminen writes:
I have some data inside a struct instance in a namespace and
I want to initialize that data before spawning a thread
which will read that data. In order to make sure that the
data will indeed get written before the other thread reads
it (ie. to make sure the compiler doesn't perform some funny
optimizations which will mess things up) I make that struct
instance volatile.
The problem is: The struct has some std::strings inside it.
I can't assign anything to these strings (at least not with
gcc). I just get an error that there's no matching
operator=. Without the 'volatile' there's no error.
Is it simply impossible to assign anything to a volatile
std::string?
I presume that you're using POSIX threads, but the same should
apply to equivalent APIs.
Generally, unless the compiler can prove to itself that a
called function will not access a specific object, the
compiler has to emit instructions that commit any modified
content to memory, before invoking the function. I don't see
any possible way for the compiler to prove that to itself, in
pthread_create()s case.
pthread_create has Posix specified semantics. The compiler
knows very well that it doesn't access user defined objects,
except those which it accesses expressedly. On the other hand,
the compiler also knows that it guarantees memory
synchronization, so won't generate code which would negate those
guarantees.
This leaves issues with CPU cache-specific issues. It's a
fairly safe bet that, as part of doing its business,
pthread_create() is going to force the CPU, in some
CPU-specific way, to flush out anything that's cached.
There's a lot more to it than just caches. But the Posix
specification guarantees full memory synchronization with
pthread_create, so the implementation will do whatever is
necessary.
So that, pretty much, covers all bases.
In other, less obvious cases, there might be some
compiler-specific ways to control some of these low-level
details. gcc, for example, has _GLIBCXX_READ_MEM_BARRIER and
_GLIBCXX_WRITE_MEM_BARRIER.
Finally, even if you're not modifying an object, you should
use a mutex to protect all access to the object. Just because
you're invoking some function that's logically defined as not
making any changes to the object, that doesn't mean that the
function won't monkey around with the object's internal
contents.
The Posix standard explicitly says that you can access an object
from multiple threads without a lock as long as no thread
modifies the object.
Some particular implementation of std::string::c_str(), for
example, might go through the trouble of explicitly adding a
trailing '\0', before returning the resulting string.
If the implementation does so in a way that won't work in a
multiple threaded environment, then that implementation is not
Posix conformant. (Note that the last time I looked, the
implementation of std::string in g++ was not Posix conformant,
and that more generally, g++ did not offer the Posix guarantees
for its library. The cases where there is really a problem,
however, are very, very few.)
So, if there's a possibility that multiple threads might
access the object simultaneously, even for supposed read-only
purposes, the access should be protected by a mutex. And the
act of invoking pthread_mutex_lock/unlock should also take
care of flushing out any modified object content.
That's the guarantee that g++ gives for its library. Posix (and
Windows, I think) requires more. (I'm fairly sure that the next
version of the C++ standard will, as well.)
application_pgp-signature_part
(You really should get rid of the above. It's not allowed under
the relevant RFC's.)
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34