简体   繁体   English

.Net CompareExchange重新排序

[英].Net CompareExchange reordering

Can the compiler or processor reorder the following instructions so that another Thread sees a == 0 and b == 1 ? 编译器或处理器是否可以重新排序以下指令,以便另一个线程看到a == 0b == 1

Assuming int a = 0, b = 0; 假设int a = 0, b = 0; somewhere. 某处。

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

No. Using Interlock will signal a full memory fence. 不可以。使用Interlock会发出完整的内存栅栏信号。 “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 . “也就是说,之前调用的任何变量写入Interlocked方法中的之前执行Interlocked方法,以及该呼叫的呼叫之后,执行之后的任何变量的读取。” [1],他们使用挥发性读/写方法,以防止在b = 1之前a = 1

[1]: Jeffrey Richter: “CLR via C# - Third Edition” part V Threading, page 803 [1]:Jeffrey Richter:“CLR通过C# - 第三版”第V部分线程,第803页

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. 组成CompareExchange操作的各个操作无法被可观察地重新排序,但是对于CompareExchange的两次调用可以从另一个线程的角度重新排序,只要执行此代码的线程无法观察到这种行为。

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). CompareExchange的同步工具阻止了影响与该操作相关的内存位置的操作之间的可观察重新排序,而不是一般的任何操作,也没有任何代码阻止编译器或JITter完全重新排序这两个CompareExchange调用(从另一个线程的角度来看)。

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 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 稍后当线程恢复工作时,两个变量都设置为1,但控制台输出将是

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. 如果您尝试使用Console.WriteLine调试无锁代码,我希望您好运。

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. 虽然a和b按顺序设置(我不认为JIT编译器会重新排序你的互锁调用)但你不能保证其他线程只能看到两个零或两个零。 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. 您可以尝试先读取b并检查它是否具有值1,然后您可以推导出a的值,但在这种情况下,您甚至不需要a的值。 That should be true at least for the x86 memory model. 至少对于x86内存模型应该如此。 That assumption can be broken by weaker memory models such as ARM. 这种假设可以通过ARM等较弱的内存模型来打破。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM