- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想在原子和非原子操作之间使用独立内存屏障(我认为无论如何这根本不重要)。我想我理解存储屏障和加载屏障的含义以及 4 种可能的内存重新排序; LoadLoad
, StoreStore
, LoadStore
, StoreLoad
。
但是,我总是发现获取/释放概念令人困惑。因为在阅读文档时,acquire不仅讲加载,还讲存储,而release不仅讲存储,还讲加载。另一方面,普通负载屏障仅为您提供负载保证,而普通存储屏障仅为您提供存储保证。
我的问题如下。在 C11/C++11 中考虑独立是否安全 atomic_thread_fence(memory_order_acquire)
作为负载屏障(防止 LoadLoad
重新排序)和 atomic_thread_fence(memory_order_release)
作为商店屏障(防止 StoreStore
重新订购)?
如果以上是正确的,我可以用什么来防止 LoadStore
和StoreLoad
重新排序?
当然,我对可移植性感兴趣,我不关心上述内容在特定平台上产生什么结果。
最佳答案
不,在宽松加载之后的获取屏障可以变成获取加载(与仅使用获取加载相比,在某些 ISA 上效率低下),因此它也必须阻止 LoadStore作为LoadLoad。
参见https://preshing.com/20120913/acquire-and-release-semantics/一些非常有用的排序图显示了这一点,并且发布存储需要确保所有先前的加载和存储都是“可见的”,因此需要阻止 StoreStore 和 LoadStore。 (商店部分为第二的重新排序)。特别是这张图:
还有https://preshing.com/20130922/acquire-and-release-fences/
https://preshing.com/20131125/acquire-and-release-fences-dont-work-the-way-youd-expect/解释了 acq 和 rel 栅栏的 2 路性质与 acq 或 rel 操作(如加载或存储)的 1 路性质。显然有些人对 atomic_thread_fence()
的保证有误解,认为它太弱了。
为了完整起见,请记住编译器必须针对 compile-time reordering 强制执行这些排序规则。 ,不仅仅是运行时。
考虑作用于 C++ 抽象机中的 C++ 加载/存储的屏障可能最有效,无论它在 asm 中如何实现。但也有像 PowerPC 这样的极端情况,其中的心理模型并不能涵盖所有内容(IRIW 重新排序,见下文)。
我确实建议尝试从获取和释放操作的角度进行思考,以确保其他操作彼此的可见性,并且绝对不要编写仅使用宽松操作和单独屏障的代码。这可以安全但效率往往较低。
<小时/>关于 ISO C/C++ 内存/线程间排序的所有内容都是根据获取加载从释放存储中查看值来正式定义的,从而创建“同步”关系,而不是关于控制本地重新排序的栅栏。
std::atomic
确实不明确保证所有线程同时看到变化的一致共享内存状态的存在。在您使用的心理模型中,在读取/写入单个共享状态时进行本地重新排序,当一个线程使其存储对某些其他线程可见之前,IRIW 重新排序可能会发生。所有其他线程。 (就像可以 happen in practice on some SMT PowerPC CPUs. )。
实践all C/C++ implementations run threads across cores that do have a cache-coherent view of shared memory因此,在读/写连贯共享内存方面的心理模型具有控制本地重新排序的障碍。但请记住,C++ 文档不会讨论重新排序,而只是讨论是否首先保证任何顺序。
<小时/>要深入了解 C++ 如何描述内存模型与实际架构的 asm 内存模型如何描述之间的区别,另请参阅 How to achieve a StoreLoad barrier in C++11? (包括我在那里的回答)。另外Does atomic_thread_fence(memory_order_seq_cst) have the semantics of a full memory barrier?是相关的。
fence(seq_cst)
包括 StoreLoad(如果该概念甚至适用于给定的 C++ 实现)。我认为根据局部障碍进行推理,然后将其转换为 C++ 基本上是可行的,但请记住,它并没有模拟 C++ 允许的 IRIW 重新排序的可能性,而这在现实生活中的某些 POWER 上会发生硬件。
另请记住,var.load(acquire)
可能比 var.load(relaxed) 更高效; fence(acquire);
在某些 ISA 上,尤其是 ARMv8。
例如this example on Godbolt ,由 GCC8.2 为 ARMv8 编译 -O2 -mcpu=cortex-a53
#include <atomic>
int bad_acquire_load(std::atomic<int> &var){
int ret = var.load(std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_acquire);
return ret;
}
bad_acquire_load(std::atomic<int>&):
ldr r0, [r0] // plain load
dmb ish // FULL BARRIER
bx lr
int normal_acquire_load(std::atomic<int> &var){
int ret = var.load(std::memory_order_acquire);
return ret;
}
normal_acquire_load(std::atomic<int>&):
lda r0, [r0] // acquire load
bx lr
关于c++ - C11 独立内存屏障 LoadLoad StoreStore LoadStore StoreLoad,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61710818/
是否应该将 store-store-barriers 放入构造函数中? 这是一个例子。最初假设 global_f = f = r = 0。一个线程A创建一个对象,赋值给一个字段,赋值给一个全局变量:
JSR133 cookbook说: StoreStore Barriers The sequence: Store1; StoreStore; Store2 ensures that Store1's
我想在原子和非原子操作之间使用独立内存屏障(我认为无论如何这根本不重要)。我想我理解存储屏障和加载屏障的含义以及 4 种可能的内存重新排序; LoadLoad , StoreStore , LoadS
我正在阅读 Hans 的一篇文章,他认为在 lazySet 或最终变量写入之前也需要 LoadStore。 他展示了一种我无法理解的特殊竞争条件。 http://www.hboehm.info/c++
我是一名优秀的程序员,十分优秀!