Volatile Violates its main job?

.net, c#, multithreading, thread-safety, volatile

Solution

The MSDN documentation is wrong. That is most certainly not what `volatile` does. The C# specification tells you exactly what `volatile` does and getting a "fresh read" or a "committed write" is not one of them. The specification is correct. `volatile` only guarantees acquire-fences on reads and release-fences on writes. These are defined as below.

- acquire-fence: A memory barrier in which other reads and writes are not allowed to move before the fence.

- release-fence: A memory barrier in which other reads and writes are not allowed to move after the fence.

I will try to explain the table using my arrow notation. A ↓ arrow will mark a volatile read and a ↑ arrow will mark a volatile write. No instruction can move through the arrowhead. Think of the arrowhead as pushing everything away.

In the following analysis I will use to variables; `x` and `y`. I will also assume that they are marked as `volatile`.

Case #1

Notice how the placement of the arrow after the read of `x` prevents the read of `y` from moving up. Also notice that the volatility of `y` is irrelevant in this case.

var localx = x;
↓
var localy = y;
↓

Case #2

Notice how the placement of the arrow after the read of `x` prevents the write to `y` from moving up. Also notice that the volatility of either of `x` or `y`, but not both, could have been omitted in this case.

var localx = x;
↓
↑
y = 1;

Case #3

Notice how the placement of the arrow before the write to `y` prevents the write to `x` from moving down. Notice that the volatility of `x` is irrelevant in this case.

↑
x = 1;
↑
y = 2;

Case #4

Notice that there is no barrier between the write to `x` and the read of `y`. Because of this the either the write to `x` can float down or the read of `y` can float up. Either movement is valid. This is why the instructions in the write-read case can be swapped.

↑
x = 1;
var localy = y;
↓

Notable Mentions

It is also important to note that:

- x86 hardware has volatile semantics on writes.

- Microsoft's implementation of the CLI (and suspect Mono's as well) has volatile semantics on writes.

- The ECMA specification does not have volatile semantics on writes.

Problem

According to MSDN: The volatile keyword indicates that a field might be modified by multiple threads that are executing at the same time. Fields that are declared volatile are not subject to compiler optimizations that assume access by a single thread. This ensures that the most up-to-date value is present in the field at all times. Please notice the last sentence: This ensures that the most up-to-date value is present in the field at all times. However, there's a problem with this keyword. I've read that it can change order of instructions: ``` First instruction Second instruction Can they be swapped? Read Read No Read Write No Write Write No Write Read Yes! <---- ``` This means John sets a value to a volatile field, and later Paul wants to read the field, Paul is getting the old value! What is going here ? Isn't that it's main job ? I know there are other solutions, but my question is about the volatile keyword. Should I (as a programmer) need to prevent using this keyword - because of such weird behavior ?

Original source

Related problems