Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.Net CompareExchange reordering

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);
like image 427
ominug Avatar asked Aug 25 '14 20:08

ominug


3 Answers

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

like image 72
Onosa Avatar answered Oct 17 '22 01:10

Onosa


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.

like image 20
Alois Kraus Avatar answered Oct 17 '22 02:10

Alois Kraus


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).

like image 3
Servy Avatar answered Oct 17 '22 03:10

Servy