In the code below will read1
be always equal to read2
, provided property Flag
can be changed from other threads? Concern here is that
According to the documentation
The volatile keyword indicates that a field can be modified in the program by something such as the operating system, the hardware, or a concurrently executing thread. ... Using the volatile modifier ensures that one thread retrieves the most up-to-date value written by another thread.
To sum up the other replies, in this situation, what happens to the values of the two variables after the code is executed can't be predicted. Both because the CLR and compiler are largely black boxes to us, and because any sort of prediction regarding the outcome of a race condition is really a gamble that's bound to be wrong at some point.
Regardless, you cannot write code of this sort in a multi-threaded environment.
Yes it can be changed naturally.
Even in the code provided it's not guranteed that read1
would be equal to read2
.
Considering that meanwhile /* some more code */
executed, Flag
can be affected by other threads.
EDIT
The equality of read1
and read2
has nothing to do with inlining or not, Flag
is a bool
, so it's a value type. So
var read1 = Flag;
//let's say read1 TRUEFlag = False
var read2 = Flag;
//read2 is FALSE, but read1 remains TRUEThis is valid in non multithreaded environment too, cause you operating on value type.
If this is not what you're asking for, please clarify.
The lack of volatile for an autoproperty is disappointing. I discovered that when using a struct with [StructLayout(LayoutKind.Sequential, Pack = 4)] and Marshal.PtrToStructure the byte layout is not preserved as expected if an autoproperty is used. What I did was use private backing fields and put the properties at the end.
if Flag can be changed from other threads, there is no guarantee that read1 and read2 will be the same. You would have to use a monitor/mutex surrounding your code and also make sure that the Flag setter also respects that mutex.
No, the property is not volatile
.
While I have not been able to obtain a satisfactory demonstration for your initial scenario, this alternative method should prove the statement nicely:
class Program
{
public bool Flag { get; set; }
public void VolatilityTest()
{
bool work = false;
while (!Flag)
{
work = !work; // fake work simulation
}
}
static void Main(string[] args)
{
Program p = new Program();
var t = new Thread(p.VolatilityTest);
t.Start();
Thread.Sleep(1000);
p.Flag = true;
t.Join();
}
}
Building this in Release mode will make the program deadlock, hence proving that Flag
does not have volatile behavior (i.e. it gets "optimized" between reads).
Replacing public bool Flag { get; set; }
with public volatile bool Flag;
will make the program terminate correctly.