Adding the volatile
keyword to a field indicates to the compiler that the field's value may be changed by multiple separate threads. The primary purpose of the volatile
keyword is to prevent compiler optimizations that assume only single-threaded access. Using volatile
ensures that the value of the field is the most recent value that is available, and the value is not subject to the caching that non-volatile values are.
It is good practice to mark every variable that may be used by multiple threads as volatile
to prevent unexpected behavior due to behind-the-scenes optimizations. Consider the following code block:
public class Example
{
public int x;
public void DoStuff()
{
x = 5;
// the compiler will optimize this to y = 15
var y = x + 10;
/* the value of x will always be the current value, but y will always be "15" */
Debug.WriteLine("x = " + x + ", y = " + y);
}
}
In the above code-block, the compiler reads the statements x = 5
and y = x + 10
and determines that the value of y
will always end up as 15. Thus, it will optimize the last statement as y = 15
. However, the variable x
is in fact a public
field and the value of x
may be modified at runtime through a different thread acting on this field separately. Now consider this modified code-block. Do note that the field x
is now declared as volatile
.
public class Example
{
public volatile int x;
public void DoStuff()
{
x = 5;
// the compiler no longer optimizes this statement
var y = x + 10;
/* the value of x and y will always be the correct values */
Debug.WriteLine("x = " + x + ", y = " + y);
}
}
Now, the compiler looks for read usages of the field x
and ensures that the current value of the field is always retrieved. This ensures that even if multiple threads are reading and writing to this field, the current value of x
is always retrieved.
volatile
can only be used on fields within class
es or struct
s. The following is not valid:
public void MyMethod() {volatileint x; }
volatile
can only be applied to fields of following types:
sbyte
, byte
, short
, ushort
, int
, uint
, char
, float
, and bool
byte
, sbyte
, short
, ushort
, int
or uint
IntPtr
and UIntPtr
Remarks:
volatile
modifier is usually used for a field that is accessed by multiple threads without using the lock statement to serialize access.volatile
keyword can be applied to fields of reference typesvolatile
keyword will not make operating on 64-bit primitives on a 32-bit platform atomic. Interlocked operations such as Interlocked.Read
and Interlocked.Exchange
must still be used for safe multi-threaded access on these platforms.