2011-12-21 50 views
3

假设我们有一个多线程的C程序(pthreads),并且各个线程的(非同步)共享变量访问不会被编译器重新排序。 x86 CPU是否尊重共享变量访问的顺序(在单个线程中),还是有可能重新排序某些内存访问?多线程和无序执行

+0

无序/推测调度执行只存在于微代码级别(后端)。 (请通知@我,因为我没有手动检查答案) – user2284570 2013-11-23 01:47:22

回答

0

非同步共享变量访问是危险的,并且乱序是其原因之一。
x86保持写入顺序(在一个线程内),但不能读取。

如果您认为订单仍然存在,这可能会让您陷入困境。例如:
线程A写入x然后写入y。假设编译器没有对它重新排序,CPU不会重新排序(x86不会,其他可能)。
线程B读取y,然后读取x。你可能会认为,如果它具有y的新价值,那么你肯定也会得到x的新价值。
并非如此。 CPU可能会对线程B的读取进行重新排序,所以y会被更早读取。

编辑:为“单向的男人”中指出,在这种情况下,X86保证排序(但不是所有的处理器!)。
我引用英特尔软件开发人员手册:

写入由单个处理器中所有 处理器相同的顺序观察。

这对于多处理器写入来说并不正确 - 它们看起来可能被不同的处理器按不同的顺序排列。

但是,我强烈建议不要依赖它,并使用适当的同步来代替。
同步原语是通过原子操作和/或障碍来实现的,它们保证您的安全。

+0

您是否可以用另一次读取重新排序读取? “线程B读取y然后读取x,您可能会认为如果它获得了y的新值,那么您肯定也会得到x的新值。”我不认为这是真实的根据英特尔手册:“读取不会与其他读取重新排序”。阅读可以重新排序与旧的写作虽然。 – 2013-09-09 20:33:32

+0

@ManofOneWay,你说得对。该手册还指出“所有处理器以相同顺序观察单个处理器写入”。我认为,我的底线是正确的 - 根据这些细节编写正确的无同步代码几乎是不可能的。 – ugoren 2013-09-10 08:51:58

+0

x86在加载和旧存储时不保证排序,因此如果存在A然后是加载B,并且它们引用不同的存储位置,则加载B可能会在A之前移动。因此,隔离仍然存在在某些情况下需要。 – 2013-09-10 09:02:07