On Thursday, 9 July 2015 at 14:03:18 UTC, Jonathan M Davis wrote:
Well, the compiler is free to assume that a variable that is
not marked as shared is thread-local. So, it's free to make
optimizations based on that. So, for instance, it can know for
a fact that
auto foo = getFoo();
auto result1 = foo.constPureFunction(); // This function
_cannot_ mutate foo
auto result2 = foo.constPureFunction(); // This function
_cannot_ mutate foo
auto bar = foo;
So, it knows that the value of bar is identical to the value of
foo and that result1 and result2 are guaranteed to be the same,
Pretty sure that's the same as in C++. Unless there was an
acquire operation/barrier in there, the compiler is free to
assume that two sequential reads to a memory location, without an
intervening write (only considering the same thread), will return
the same result. The optimisations that are forbidden in C++ are
more subtle.
Really, we can't tell what subtle behavioral problems you're
risking with __gshared, because that depends on what the
compiler is currently able to do with the assumption that a
variable is in TLS. You run into all of the problems that you
risk with sharing variables in threads in C++ only worse,
because the D compiler is free to assume that an object is
thread-local unless it's marked as shared and thus can make
optimizations based on that, whereas the C++ compiler can't.
And you've thrown away all of the compiler's help by using
__gshared. __gshared is intended specifically for use with
interacting with C code where we don't really have a choice,
and you have to be careful with it.
Basically, __gshared pretends to compatible with C(++) globals,
but in actual fact it doesn't share the same memory model so who
knows what might happen... It's not just
dangerous-so-be-very-careful, it's fundamentally broken and we're
currently just getting away with it by relying on C(++)
optimisers.