.Net CompareExchange reordering

423 Views Asked by At

Can the compiler or processor reorder the following instructions so that another Thread sees a == 0 and b == 1?

Assuming int a = 0, b = 0; somewhere.

System.Threading.Interlocked.CompareExchange<int>(ref a, 1, 0);
System.Threading.Interlocked.CompareExchange<int>(ref b, 1, 0);
3

There are 3 best solutions below

6
On BEST ANSWER

No. Using Interlock will signal a full memory fence. “That is, any variable writes before the call to an Interlocked method execute before the Interlocked method, and any variable reads after the call executes after the call.” [1] They use volatile read/write methods to prevent the b = 1 before a = 1.

[1]: Jeffrey Richter: “CLR via C# - Third Edition” part V Threading, page 803

1
On

Sure it can. The individual operations that compose the CompareExchange operation cannot be observably re-ordered, but the two calls to CompareExchange can be reordered from the perspective of another thread, so long as the thread executing this code cannot observe such behavior.

The synchronization tools in place for CompareExchange are preventing observable reordering between the operations affecting the memory locations relevant to that operation, not any operations in general, nor is there anything in that code to prevent the compiler or JITter from reordering these two CompareExchange calls entirely (from the perspective of another thread).

2
On

You are reading too much theory. Yes it can happen in practice if the other thread does

Console.WriteLine("a: {0}, b: {1}", a, b);

Since String.Format which is used to format the string has a signature of

   String Format(string fmt, params object[] args)
   {
       ....
   }

your integers will get copied because of boxing. The only condition which needs to be true is that the threads time slice ends when it has copied a in its unitialized state. Later when the thread resumes work both variables are set to one but your Console output will be

a: 0, b: 1

The point of seeing other values happens immediately if you are working with copies of values without realizing it. That is the reason why you let usually other people write correct lock free code. If try you debug lock free code with Console.WriteLine I wish you good luck with it.

Although a and b are set in order (I do not think the JIT compiler will reorder your interlocked calls) you have no guarantee that other threads see only two zeros or two ones. You could try to read first b and check if it has the value one then you can deduce the value of a but in that case you would not even need the value of a anyway. That should be true at least for the x86 memory model. That assumption can be broken by weaker memory models such as ARM.