I wonder whether you have misunderstood what volatile
means. Volatile can be used with types that can be read or written as an atomic action.
There is no acquire/release of a lock, only a barrier to compile-time and run-time reordering to provide lockless aquire/release semantics (https://preshing.com/20120913/acquire-and-release-semantics/). On non-x86 this may require barrier instructions in the asm, but not taking a lock.
volatile
indicates that a field may be modified by other threads, which is why read/writes need to be treated as atomic and not optimised.
Your question is a little ambiguous.
1/ If you mean, will the compiler transform:
var local = something;
if (local != null) local.DoThings();
into:
if (something != null) something.DoThings();
then the answer is no.
2/ If you mean, will "DoThings()
" be called twice on the same object:
var local = something;
if (local != null) local.DoThings();
if (something != null) something.DoThings();
then the answer is mostly yes, unless another thread has changed the value of "something
" before the second "DoThings()
" is invoked. If this is the case then it could give you a run time error - if after the "if
" condition is evaluated and before "DoThings
" is called, another thread sets "something
" to null
then you will get a runtime error. I assume this is why you have your "var local = something;
".
3/ If you mean will the following cause two reads:
if (something != null) something.DoThings();
then yes, one read for the condition and a second read when it invokes DoThings()
(assuming that something
is not null). Were it not marked volatile
then the compiler might manage that with a single read.
In any event the implementation of the function "DoThings()
" needs to be aware that it could be called by multiple threads, so would need to consider incorporating a combination of locks and its own volatile members.