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 volatile keyword in C# is used to inform the JIT compiler that the value of the variable should never be cached because it might be changed by the operating system, the hardware, or a concurrently executing thread.
That is, as far as I understand, when you use the Visual C++ compiler, a volatile bool is for most practical purposes an atomic<bool> . It should be noted that newer VS versions add a /volatile switch that controls this behavior, so this only holds if /volatile:ms is active.
Well you are right. It is more elaborated in Joseph Albahari threading book/article.
The MSDN documentation states that use of the volatile keyword ensures that the most up-to-date value is present in the field at all times. This is incorrect, since as we’ve seen, a write followed by a read can be reordered.
http://www.albahari.com/threading/part4.aspx#_The_volatile_keyword
Should I ( as a programmer ) need to prevent using this keyword-because of such weird behavior?
It should be used only after knowing this weired behavior. It should not be used as a Magic keyword to retrieve latest values all the time in multithreaded environment.
IMO, usage of volatile keyword should be avoided as probable bugs are hard to find out.
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:
Another point raised by Joseph Albahari is that process architecture can adversely impact volatile, i.e. AMD in particular can cause values to be swapped.
Since you will probably have no idea what system type your application will run on in production its best to always avoid the volatile keyword.
Also slightly off topic you should always avoid the ReaderWriterLock class as under heavy load on multiprocessor systems this can allow multiple write locks please see here to be taken simultaneously which will cause application hangs which will be extremely difficult to root cause
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