Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Volatile.Read take ref parameter?

The implementation of Volatile.Read merely inserts a memory barrier after the read:

public static int Read(ref int location)
{
    var value = location;
    Thread.MemoryBarrier();
    return value;
}

Thus, usage of the method like so...

return Volatile.Read(ref _a) + Volatile.Read(ref _b);

...would be equivalent to:

var a = _a;
Thread.MemoryBarrier();
var b = _b;
Thread.MemoryBarrier();
return a + b;

Given the above, wouldn't the resulting behavior be identical if the parameter was not a ref?

public static int Read(int value)
{
    Thread.MemoryBarrier();
    return value;
}

I guess that the ref parameter was used simply to prevent programmers from passing things other than variables, such as Volatile.Read(2 + 3). Can anyone see any other reason for the ref when variables are passed in?

like image 586
Douglas Avatar asked May 20 '17 12:05

Douglas


1 Answers

That is not what the real code looks like after the jitter is done with it. Volatile.Read() is an intrinsic. An expensive word that means that the jitter will not compile the method at all but substitutes it with a processor-specific version of the machine code. The code you found is just a place-holder that could serve as a fallback on a machine without a decent jitter. Theoretically.

You can see what you get on your machine with Debug > Windows > Disassembly. You have to switch to the Release build and use Tools > Options > Debugging > General > untick "Suppress JIT optimization". Most programmers will be happy with what they see:

04CF0450  mov         ecx,dword ptr ds:[7C43ACh] 

Or in other words: nothing. Just a plain memory read without a barrier. Intel/AMD cores have a strong memory model that doesn't require a barrier. But, say, an ARM core does and will need the address of the variable. Itanium was also weak, but its jitter was discontinued.

Do note how, while you could be happy, that this is also rather bad news. You basically can't rely on testing your program on your dev machine and conclude it is good enough. Or in other words, no way to tell that you should have used Volatile but you forgot. Only running your program on the device is going to give you a hint that you got it wrong. It does take a lot of courage to skip lock :)

Several more intrinsics around like that, Math.Sqrt() for example. Most processors have it as a built-in machine code instruction.

like image 145
Hans Passant Avatar answered Sep 24 '22 07:09

Hans Passant