views:

211

answers:

1

I'm looking at the implementation of the VolatileRead/VolatileWrite methods (using Reflector), and i'm puzzled by something.

This is the implementation for VolatileRead:

[MethodImpl(MethodImplOptions.NoInlining)]
public static int VolatileRead(ref int address)
{
    int num = address;
    MemoryBarrier();
    return num;
}

How come the memory barrier is placed after reading the value of "address"? dosen't it supposed to be the opposite? (place before reading the value, so any pending writes to "address" will be completed by the time we make the actual read. The same thing goes to VolatileWrite, where the memory barrier is place before the assignment of the value. Why is that? Also, why does these methods have the NoInlining attribute? what could happen if they were inlined?

+6  A: 

I thought that until recently. Volatile reads aren't what you think they are - they're not about guaranteeing that they get the most recent value; they're about making sure that no read which is later in the program code is moved to before this read. That's what the spec guarantees - and likewise for volatile writes, it guarantees that no earlier write is moved to after the volatile one.

You're not alone in suspecting this code, but Joe Duffy explains it better than I can :)

My answer to this is to give up on lock-free coding other than by using things like PFX which are designed to insulate me from it. The memory model is just too hard for me - I'll leave it to the experts, and stick with things that I know are safe.

One day I'll update my threading article to reflect this, but I think I need to be able to discuss it more sensibly first...

(I don't know about the no-inlining part, btw. I suspect that inlining could introduce some other optimizations which aren't meant to happen around volatile reads/writes, but I could easily be wrong...)

Jon Skeet
+1 for the links. I really should buy Joe Duffy's book.
RichardOD
+1 for correct. Also, I <3 Joe Duffy's blog. :)
Greg D
@RichardOD: It's a great book, and he's already working on a second edition. :)
Greg D
this means that when i use Thread.VolatileRead i'm not guaranteed to get the last value to be written to the variable?
opc: Not strictly speaking, no (despite what MSDN says) - although I believe in almost any realistic case you actually *will* get the last value.
Jon Skeet
MSDN says this: " VolatileWrite ensures that a value written to a memory location is immediately visible to all processors. This might require flushing processor caches", so the "flushing caches" is under the responsbility of the user? since we can see that calling VolatileWrite dosen't wait until the store buffer is empty .. this would mean that the documentation in MSDN is totally wrong and misleading .. or am I wrong about something here?
@opc: MSDN is confusing on this one I'm afraid. Follow the link to Joe Duffy's blog for more information.
Jon Skeet
@Jon, I did, but I'm afraid he's not too clear also about the "freshness" of data part//
@opc: I think the basic point is that it's guaranteed that anything else you read afterwards will be at least as fresh. So you can make sensible decisions, if you get your reads and writes in the right order. It's *possible* that the memory barrier is achieved precisely by reading/writing freshly - but it's not guaranteed by the spec :(
Jon Skeet