Possible Duplicate:
Why we need Thread.MemoryBarrier()?
From O'Reilly's C# in a Nutshell:
class Foo
{
int _answer;
bool _complete;
void A()
{
_answer = 123;
Thread.MemoryBarrier(); // Barrier 1
_complete = true;
Thread.MemoryBarrier(); // Barrier 2
}
void B()
{
Thread.MemoryBarrier(); // Barrier 3
if (_complete)
{
Thread.MemoryBarrier(); // Barrier 4
Console.WriteLine (_answer);
}
}
}
Suppose methods A and B ran concurrently on different threads:
The author says: "Barriers 1 and 4 prevent this example from writing “0”. Barriers 2 and 3 provide a freshness guarantee: they ensure that if B ran after A, reading _complete would evaluate to true."
My questions are:
Memory barrier enforces ordering constraint on reads and writes from/to memory: memory access operations before the barrier happen-before the memory access after the barrier.
Barriers 1 and 4 have complementary roles: barrier 1 ensures that the write to _answer
happens-before the write to _complete
, while barrier 4 ensures that the read from _complete
happens-before the read from _answer
. Imagine barrier 4 isn't there, but barrier 1 is. While it is guaranteed that 123
is written to _answer
before true
is written to _complete
some other thread running B()
may still have its read operations reordered and hence it may read _answer
before it reads _complete
. Similarly if barrier 1 is removed with barrier 4 kept: while the read from _complete
in B()
will always happen-before the read from _answer
, _complete
could still be written to before _answer
by some other thread running A()
.
Barriers 2 and 3 provide freshness guarantee: if barrier 3 is executed after barrier 2 then the state visible to the thread running A()
at the point when it executes barrier 2 becomes visible to the thread running B()
at the point when it executes barrier 3. In the absence of any of these two barriers B()
executing after A()
completed might not see the changes made by A()
. In particular barrier 2 prevents the value written to _complete
from being cached by the processor running A()
and forces the processor to write it out to the main memory. Similarly, barrier 3 prevents the processor running B()
from relying on cache for the value of _complete
forcing a read from the main memory. Note however that stale cache isn't the only thing which can prevent freshness guarantee in the absence of memory barriers 2 and 3. Reordering of operations on the memory bus is another example of such mechanism.
Memory barrier just ensures that the effects of memory access operations are ordered across the barrier. Other instructions (e.g. increment a value in a register) may still be reordered.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With