Hi there,
I have a few questions about what is safe to assume when writing
concurrent code in D with data sharing (as opposed to message
passing).
After doing a fair amount of reading, I'm still slightly hazy
about what shared does and doesn't guarantee. Here is the only
assumption I understand to be valid:
* Reads and writes to shared variables with a size equal to or
less than the word size of the machine are atomic and are visible
to all other threads immediately.
Now, in Andrei's D book he also states that sequential
consistency is guaranteed for operations on shared data, however
I understand that this is not currently implemented by (any?)
compiler and perhaps never will be, what with the discussions
about making changes to the semantics of shared and all.
So then this code is not safe, assuming the methods are executed
on different threads:
shared int x = 0;
shared bool complete = false;
void foo()
{
x = 7; // atomic
complete = true; // atomic
}
void bar()
{
while (!complete) {}
writeln(x); // undefined output (0 or 7)
}
But then I understand the core.atomic module incorporates the
necessary memory barriers to make this work, so we can replace
foo() by:
void foo()
{
x.atomicStore(7);
complete.atomicStore(true);
}
and achieve the intended behaviour (maybe only one of those two
modifications were actually needed here?). Or possibly:
void foo()
{
x = 7; // atomic
atomicFence(); // from core.atomic again
complete = true; // atomic
}
Do these modifications achieve the desired result? I know there
are other ways to go about this. I think one (bad) way is putting
a mutex around every read/write (a mutex also acts as a memory
barrier, right?), and I suppose in this case, message passing!
(But let's pretend the data sharing is more complex)
My other question about shared is: what does the shared qualifier
mean when applied to a class definition? e.g.
shared class Cat {...}
Does it just force all references to Cat instances to be shared
by default and make all methods of Cat shared? Andrei uses it in
his book when talking about lock-free programming with cas,
however he seems to make the assumption (well, explicitly states)
that sequential consistency is assured within the methods of such
a class. I'm quite confused about what it actually means,
especially since shared apparently does not currently use memory
barriers.