ominug
ominug

Reputation: 1572

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

Upvotes: 7

Views: 429

Answers (3)

Servy
Servy

Reputation: 203802

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

Upvotes: 4

Onosa
Onosa

Reputation: 1273

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

Upvotes: 6

Alois Kraus
Alois Kraus

Reputation: 13535

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.

Upvotes: 3

Related Questions