2017-07-08 62 views
0

我一直在阅读内存重新排序最近。我的问题是关于多线程场景。考虑下面的例子:内存订购,超出其他执行和多线程安全

A = 0; 
B = 0; 

Thread 1 on Processor 1      Thread 2 on Processor 2 

    A = 100;          while(B== 0); 
    B = 1;          //access A here 

我一直在编码上X86-64 Windows平台上,从来没有认为商店A和B可以被重新排序(无论是在编译器级或硬件级),我最终可能线程2中的B = 0,并且发现A仍然是0.并且从来没有遇到任何问题或者使用这样的代码讨厌的bug。这是因为x86-x64的强烈排序,windows C编译器也是如此。

对于这样的代码,要在任何其他弱平台内存平台上执行,是否需要确保我更新并访问锁内的A和B(假设底层锁实现使用内存屏障并使锁定为锁只有在所有处理器内核都可见之前的所有加载和存储之后才会被释放)。

感谢

回答

1

是因为x86的64位被强有序等等都是窗口的C编译器。

确实,X86是一个强烈订购的CPU,不允许存储重新排序。所以所有的CPU核心都会观察编译器发出的命令。

但是,B在处理器1上被修改,而在处理器2上被读取。如果没有同步(尝试最大化编译器优化,它可能会停止工作),C存储器模型将不允许这样做。

尽管可以使用锁定来在内核之间进行同步,但由于您正在旋转B,因此可能会出现问题。如果发生这种情况,处理器1无法更新该值。

一个正确的解决方案是使Batomic。这将保证所有级别的正确订购。

+0

LMimsey您的意思是最大限度地优化可以使编译器级别重新排序。我没有得到“这在C内存模型中是不允许的”。当B = 1时,强有序的x86应该保证A = 100,这是上面例子的意图。 – san216

+0

另外我的问题的下一部分,在内存有限的平台上,我是否需要注意,我在锁内更新A和B.在所有操作系统平台上锁定原语是否会在锁定释放逻辑内部插入内存障碍,因为否则,甚至锁定可能无法防范硬件存储器访问重新排序。 – san216

+0

对2个或更多线程的单个内存位置的读/写访问违反了内存模型规则(又名数据竞赛)。结果是未定义的行为。例如,由于你的编译器可能不希望在核心2上更新'B',它可能会简单地将它从循环中取出。循环将永远不会退出。 – LWimsey