3

我正在阅读有关内存屏障的内容,我可以总结的是它们阻止了编译器完成的指令重新排序。

所以在用户空间内存中可以说我有

b = 0;
main(){

a = 10;
b = 20;
c = add(a,b);

}

编译器是否可以重新排序此代码,以便在调用b = 20之后进行分配。c = add()

为什么我们在这种情况下不使用障碍?我在这里缺少一些基本知识吗?

虚拟内存是否免于任何重新排序?

进一步扩展问题:

在网络驱动程序中:

1742         /*
1743          * Writing to TxStatus triggers a DMA transfer of the data
1744          * copied to tp->tx_buf[entry] above. Use a memory barrier
1745          * to make sure that the device sees the updated data.
1746          */
1747         wmb();
1748         RTL_W32_F (TxStatus0 + (entry * sizeof (u32)),
1749                    tp->tx_flag | max(len, (unsigned int)ETH_ZLEN));
1750 

当他说设备看到更新的数据时......如何将其与使用障碍的多线程理论联系起来。

4

3 回答 3

4

简短的回答

内存屏障在用户模式代码中的使用频率低于内核模式代码,因为用户模式代码倾向于使用更高级别的抽象(例如 pthread 同步操作)。

额外细节

在分析可能的操作顺序时,需要考虑两件事:

  1. 执行代码的线程将以什么顺序查看操作
  2. 其他线程将以什么顺序查看操作

在您的示例中,编译器无法重新排序b=20c=add(a,b)因为该c=add(a,b)操作使用b=20. 但是,编译器可能会重新排序这些操作,以便其他线程在与更改相关联c的内存位置之前看到与更改相关联的内存位置b

这是否真的会发生取决于硬件实现的内存一致性模型。

至于编译器何时可能进行重新排序,您可以想象添加另一个变量,如下所示:

b = 0;
main(){

a = 10;
b = 20;
d = 30;
c = add(a,b);

}

在这种情况下,编译器可以自由地将d=30赋值移动到c=add(a,b).

然而,整个例子太简单了。该程序不做任何事情,编译器可以消除所有操作,并且不需要将任何内容写入内存。

附录:内存重新排序示例

在多处理器环境中,多个线程可以看到内存操作以不同的顺序发生。英特尔软件开发人员手册在第 3 卷第 8.2.3 节中有一些示例。我在下面复制了一个屏幕截图,显示了一个可以重新排序加载和存储的示例。还有一篇很好的博客文章提供了有关此示例的更多详细信息。

使用较早的商店重新排序的负载到不同的位置

于 2016-03-22T17:59:38.233 回答
2

运行代码的线程总是会表现得好像它自己代码的源代码行的影响是按程序顺序发生的一样。这就好像规则是启用大多数编译器优化的原因。

在单个线程中,无序 CPU 跟踪依赖关系,以使线程产生其所有指令都按程序顺序执行的错觉。不过,其他核心可能会看到全局可见(对其他核心上的线程)的影响。

只有在通过共享内存与其他线程交互的代码中才需要内存屏障(作为锁定的一部分,或单独使用)。

编译器可以类似地进行任何他们想要的重新排序/提升,只要结果相同。C++ 内存模型非常弱,因此即使针对 x86 CPU 也可以进行编译时重新排序。(但当然不是在本地线程中产生不同结果的重新排序。)C11<stdatomic.h>和等效的 C++11std::atomic是告诉编译器您对操作的全局可见性有任何排序要求的最佳方式。在 x86 上,这通常只会导致将存储指令按源顺序放置,但默认情况下每个存储都memory_order_seq_cst需要一个MFENCE,以防止 StoreLoad 重新排序以实现完全的顺序一致性。

在内核代码中,内存屏障也很常见,以确保以所需的顺序存储到内存映射的 I/O 寄存器。推理是相同的:对一系列存储和加载的内存排序全局可见的影响。不同之处在于观察者是一个 I/O 设备,而不是另一个 CPU 上的线程。核心通过缓存一致性协议相互交互的事实是无关紧要的。

于 2016-03-23T03:34:46.257 回答
1

编译器不能重新排序(运行时或 cpu 也不能),所以b=20在之后,c=add()因为这会改变方法的语义,这是不允许的。我会说编译器(或运行时或 cpu)按照你的描述行事会使行为随机化,这将是一件坏事。

这种对重新排序的限制仅适用于执行代码的线程。正如@GabrielSouthern 指出的那样,如果 、 和 都是全局变量,则无法保证商店的顺序变得a全局b可见c

于 2016-03-22T10:03:22.483 回答