c++ - 在 C++ 中,加载是否可以在获取操作下方滑动/存储可以在释放上方 float 吗?

标签 c++ concurrency atomic memory-barriers memory-model

TL/DR:获取/释放操作是否只允许 4 次重新排序中的 1 次(而不是 2 次)?如果是这样,为什么?

目前,我对获取-释放语义的理解是(基本上)

  • 获取操作不允许其下方的加载/存储 float 在其上方
  • 释放操作不允许其上方的加载/存储滑到其下方

但关于相反方向的说法较少。

从一些来源(Jeff Preshing 和其他人的博客,以及一些架构手册似乎暗示这一点)我读到,获取/释放操作相当于(给定内存位置上的原子操作 + 内存屏障)/(内存屏障+ 原子操作)相应地。

他们描述了 4 种内存障碍,并表示例如获取操作使用类似于 LoadLoad + LoadStore 的屏障(与释放类似)。

据我了解,这些障碍(相应的 LoadLoad + LoadStore 和 StoreStore + LoadStore)仅允许:

  • 一家商店滑入收购

  • 负载漂浮在释放上方

并且负载不能在获取下方滑动/存储不能 float 在释放上方。

这通常是正确的吗?这对于 C++ 来说正确吗? C++ 与一般含义有什么不同吗?

(因为例如 this 答案说负载可以在获取下方滑动(据我所知)。我还有一些消息来源说任何东西都可以在获取下方滑动(反之亦然)。)

如果这是正确的,其理由是什么?我试图想出类似的东西(用于发布):

x.store(5, std::memory_order_release);
y.store(true, std::memory_order_relaxed);

考虑到它用于双重检查锁定等模式,不同的线程以不同的顺序读取它们将是一件坏事。

这接近一个原因吗?如果是这样,有人可以给出获取和释放的可靠示例吗?

虽然对于在获取下方滑动的存储/ float 在发布上方的加载来说,(可能)没有这样的缺点......

最佳答案

内存屏障可用于实现加载-获取和存储-释放语义,但它们提供的保证比所需的更严格,如 Jeff Preshing's article 中所述。 :

Please note that these barriers are technically more strict than what’s required for acquire and release semantics on a single memory operation, but they do achieve the desired effect.

如果在加载获取和后续内存操作之间放置 LoadLoad + LoadStore 屏障,则程序顺序中屏障之前的所有加载都无法在屏障之后重新排序,并且所有后续内存访问都无法在屏障之前重新排序。障碍。这比为特定加载操作实现获取语义所必需的更加严格,因为屏障对所有先前的加载进行排序,而不仅仅是需要具有获取语义的特定加载。所以它们并不完全等同。存储-发布语义也是如此。 Herb Stutter 对此发表了评论:

Yes, this is a bug in my presentation (the words more than the actual slide). The example is fine but I should fix the description of "if this was a release fence." In particular:

starting at 1:10:30, I was incorrect to say that a release fence has a correctness problem because it allows stores to float up (it does not, as noted the rule is in 29.8.2; thanks!) – what I should have said was that it’s a still a performance pessimization because the fence is not associated with THAT intended store, but since we don’t know which following store it has to pessimistically apply to ALL ensuing ordinary stores until the next applicable special memory operation synchronization point – it pushes them all down and often doesn’t need to

加载获取和存储释放语义通过 LoadLoad、LoadStore 和 StoreStore 屏障实现的原因是因为 ISA 只提供此类屏障。有一些研究建议提出了更灵活或可配置的屏障,这些屏障可能仅适用于特定的内存操作或一系列指令或指令 block ,但它们尚未应用于任何 ISA。

关于c++ - 在 C++ 中,加载是否可以在获取操作下方滑动/存储可以在释放上方 float 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51119331/

相关文章:

c++ - 编写一个递归函数来乘以 2 个整数

C++抛硬币困惑

concurrency - Clojure: Agent calling Agent: 疑似死锁?

c++ - OpenMP atomic 是否应用于行、变量名或实际内存地址?

c++ - 为什么 memory_order_relaxed 和 memory_order_seq_cst 没有区别?

c++ - 以 RAW 形式恢复磁盘内容并转储为一个大二进制文件的应用程序?

c++ - 是否在 Exit() 时调用基本对象析构函数?

c++ - 宽松的原子计数器安全吗?

java - Java 同步方法

cuda - 何时以及为何在 CUDA 中使用atomicInc()?