繁体   English   中英

.Net CompareExchange重新排序

[英].Net CompareExchange reordering

编译器或处理器是否可以重新排序以下指令,以便另一个线程看到a == 0b == 1

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

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

不可以。使用Interlock会发出完整的内存栅栏信号。 “也就是说,之前调用的任何变量写入Interlocked方法中的之前执行Interlocked方法,以及该呼叫的呼叫之后,执行之后的任何变量的读取。” [1],他们使用挥发性读/写方法,以防止在b = 1之前a = 1

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

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

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

你正在阅读太多的理论。 是的,如果其他线程可以在实践中发生

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

由于用于格式化字符串的String.Format具有签名

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

由于拳击你的整数将被复制。 唯一需要满足的条件是线程时间片在复制了其单位化状态时结束。 稍后当线程恢复工作时,两个变量都设置为1,但控制台输出将是

a: 0, b: 1

如果您在没有意识到的情况下处理值的副本,则立即发现其他值的观点。 这就是为什么你通常让其他人写正确的无锁代码的原因。 如果您尝试使用Console.WriteLine调试无锁代码,我希望您好运。

虽然a和b按顺序设置(我不认为JIT编译器会重新排序你的互锁调用)但你不能保证其他线程只能看到两个零或两个零。 您可以尝试先读取b并检查它是否具有值1,然后您可以推导出a的值,但在这种情况下,您甚至不需要a的值。 至少对于x86内存模型应该如此。 这种假设可以通过ARM等较弱的内存模型来打破。

暂无
暂无

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

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