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 ?
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.
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: