I understand the volatile
keyword in C++ fairly well. But in C#, it appears to take a different meaning, more so related to multi-threading. I thought bool operations were atomic, and I thought that if the operation were atomic, you wouldn't have threading concerns. What am I missing?

- 821
- 1
- 7
- 16
-
1`volatile` prevents instruction reordering around the variable access. It is quite complex. See http://www.albahari.com/threading/part4.aspx#_Memory_Barriers_and_Volatility – xanatos May 16 '15 at 06:38
-
[Eric Lippert's answer to another question](http://stackoverflow.com/a/26315297/517852) actually has a very good description of the differences in the semantics of volatile between C++ and C#. – Mike Zboray May 16 '15 at 07:52
2 Answers
I thought bool operations were atomic
They are are indeed atomic.
and I thought that if the operation were atomic, you wouldn't have threading concerns.
That is where you have an incomplete picture. Imagine you have two threads running on separate cores, each with their own cache layers. Thread #1 has foo
in its cache, and Thread #2 updates the value of foo
. Thread #1 won't see the change unless foo
is marked as volatile
, acquired a lock
, used the Interlocked
class, or explicitly called Thread.MemoryBarrier()
which would cause the value to be invalidated in the cache. Thus, guaranteeing that you read the most up to date value:
Using the volatile modifier ensures that one thread retrieves the most up-to-date value written by another thread.
Eric Lippert has a great post about volatility where he explains:
The true semantics of volatile reads and writes are considerably more complex than I've outlined here; in fact they do not actually guarantee that every processor stops what it is doing and updates caches to/from main memory. Rather, they provide weaker guarantees about how memory accesses before and after reads and writes may be observed to be ordered with respect to each other.
Edit:
As per @xanatos comment, This doesn't mean that volatile
guarantees an immediate read, it guarantees a read on the most updated value.

- 146,575
- 32
- 257
- 321
-
Partially wrong. a `volatile` write doesn't guarantee an immediate write. – xanatos May 16 '15 at 06:39
-
@xanatos I did not mean that it guarantees immediate writes. I ment it guarantees a read on the updated value. – Yuval Itzchakov May 16 '15 at 06:42
-
You have problems writing `volatile` :-) Twice written, twice erred :-) :-) – xanatos May 16 '15 at 06:45
-
The volatile
keyword in C# is all about reading/writing reordering, so it is something quite esoteric.
http://www.albahari.com/threading/part4.aspx#_Memory_Barriers_and_Volatility
(that I consider to be one of the "bibles" about threading) writes:
The volatile keyword instructs the compiler to generate an acquire-fence on every read from that field, and a release-fence on every write to that field. An acquire-fence prevents other reads/writes from being moved before the fence; a release-fence prevents other reads/writes from being moved after the fence. These “half-fences” are faster than full fences because they give the runtime and hardware more scope for optimization.
It is something quite unreadable :-)
Now... What it doesn't mean:
- It doesn't mean that a value will be read now/will be written now
it simply means that if you read something from a volatile variable, everything else that has been read/written before this "special" read won't be moved after this "special" read. So it creates a barrier. So paradoxically, by reading from a volatile variable, you guarantee that all the writes you have done to any other variable (volatile or not) at the point of the reading will be done.
A volatile write is something probably more important, and is something that is in part guaranteed by the Intel CPU, and something that wasn't guaranteed by the first version of Java: no write reordering. The problem was:
object myrefthatissharedwithotherthreads = new MyClass(5);
where
class MyClass
{
public int Value;
MyClass(int value)
{
Value = value;
}
}
Now... that expression can be imagined to be:
var temp = new MyClass();
temp.Value = 5;
myrefthatissharedwithotherthreads = temp;
where temp
is something generated by the compiler that you can't see.
If the writes can be reordered, you could have:
var temp = new MyClass();
myrefthatissharedwithotherthreads = temp;
temp.Value = 5;
and another thread could see a partially initialized MyClass
, because the value of myrefthatissharedwithotherthreads
is readable before the class MyClass
has finished initializing.

- 109,618
- 12
- 197
- 280
-
1More than just fences, `volatile` also prevents optimizations such as constant propagation, dead code elimination or register hoisting. It's more restrictive than simple fences around accesses. – user703016 May 16 '15 at 07:05
-
-
"An acquire(read)-fence prevents other reads/writes from being moved before the fence" and then you say "everything else that has been read/written before this "special" read won't be moved after this special read". I have a hard time consolidating these two. It seems they contradict each other. – pooya13 Aug 21 '23 at 06:34