I wanted to understand on when exactly I need to declare a variable as volatile. For that I wrote a small program and was expecting it to go into infinite loop because of missing volatility of a condition variable. It did not went into infinite loop and worked fine without volatile keyword.
Two questions:
What should I change in the below code listing - so that it absolutely requires use of volatile?
Is C# compiler smart enough to treat a variable as volatile - if it sees that a variable is being accessed from a different thread?
The above triggered more questions to me :)
a. Is volatile just a hint?
b. When should I declare a variable as volatile in context of multithreading?
c. Should all member variables be declared volatile for a thread safe class? Is that overkill?
Code Listing (Volatility and not thread safety is the focus):
class Program
{
static void Main(string[] args)
{
VolatileDemo demo = new VolatileDemo();
demo.Start();
Console.WriteLine("Completed");
Console.Read();
}
}
public class VolatileDemo
{
public VolatileDemo()
{
}
public void Start()
{
var thread = new Thread(() =>
{
Thread.Sleep(5000);
stop = true;
});
thread.Start();
while (stop == false)
Console.WriteLine("Waiting For Stop Event");
}
private bool stop = false;
}
Thanks.
Firstly, Joe Duffy says "volatile is evil" - that's good enough for me.
If you do want to think about volatile, you must think in terms of memory fences and optimisations - by the compiler, jitter and CPU.
On x86, writes are release fences, which means your background thread will flush the true
value to memory.
So, what you are looking for is a caching of the false
value in your loop predicate. The complier or jitter may optimise the predicate and only evaluate it once, but I guess it doesn't do that for a read of a class field. The CPU will not cache the false
value because you are calling Console.WriteLine
which includes a fence.
This code requires volatile
and will never terminate without a Volatile.Read
:
static void Run()
{
bool stop = false;
Task.Factory.StartNew( () => { Thread.Sleep( 1000 ); stop = true; } );
while ( !stop ) ;
}
I am not an expert in C# concurrency, but AFAIK your expectation is incorrect. Modifying a non-volatile variable from a different thread does not mean that the change will never become visible to other threads. Only that there is no guarantee when (and if) it happens. In your case it did happen (how many times did you run the program btw?), possibly due to the finishing thread flushing its changes as per @Russell's comment. But in a real life setup - involving more complex program flow, more variables, more threads - the update may happen later than 5 seconds, or - maybe once in a thousand cases - may not happen at all.
So running your program once - or even a million times - while not observing any problems only provides statistical, not absolute proof. "Absence of evidence is not evidence of absence".
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