相关疑难解决方法(0)

如何在 C++11 中实现 StoreLoad 屏障?

我想编写可移植代码(Intel、ARM、PowerPC...)来解决一个经典问题的变体:

Initially: X=Y=0

Thread A:
  X=1
  if(!Y){ do something }
Thread B:
  Y=1
  if(!X){ do something }
Run Code Online (Sandbox Code Playgroud)

其中目标是避免两个线程都在做的情况something。(如果两者都没有运行也没关系;这不是只运行一次的机制。)如果您发现我下面的推理中有一些缺陷,请纠正我。

我知道,我可以通过memory_order_seq_cstatomic stores 和loads实现目标,如下所示:

std::atomic<int> x{0},y{0};
void thread_a(){
  x.store(1);
  if(!y.load()) foo();
}
void thread_b(){
  y.store(1);
  if(!x.load()) bar();
}
Run Code Online (Sandbox Code Playgroud)

这实现了目标,因为
{x.store(1), y.store(1), y.load(), x.load()}事件必须有一些单一的总顺序,它必须与程序顺序“边缘”一致:

  • x.store(1) “在TO之前” y.load()
  • y.store(1) “在TO之前” x.load()

如果foo()被调用,那么我们有额外的优势:

  • y.load() “之前读取值” y.store(1)

如果bar()被调用,那么我们有额外的优势:

  • x.load() “之前读取值” x.store(1)

所有这些边组合在一起将形成一个循环:

x.store(1)“在TO之前”“在TO之前y.load()读取值” y.store(1)“在TO之前” x.load()“读取之前值”x.store(true)

这违反了订单没有周期的事实。

我故意使用非标准术语“在 TO …

c++ atomic memory-barriers language-lawyer stdatomic

13
推荐指数
1
解决办法
1003
查看次数

为什么这个“std::atomic_thread_fence”起作用

首先我想谈一下我对此的一些理解,如有错误请指正。

  1. aMFENCE在x86中可以保证全屏障
  2. 顺序一致性可防止 STORE-STORE、STORE-LOAD、LOAD-STORE 和 LOAD-LOAD 重新排序

    这是根据维基百科的说法。

  3. std::memory_order_seq_cst不保证防止 STORE-LOAD 重新排序。

    这是根据Alex 的回答,“负载可能会通过早期存储重新排序到不同位置”(对于 x86),并且 mfence 不会总是被添加。

    a是否std::memory_order_seq_cst表示顺序一致性?根据第2/3点,我认为这似乎不正确。std::memory_order_seq_cst仅当以下情况时才表示顺序一致性

    1. 至少一个显式MFENCE添加到任一LOADSTORE
    2. LOAD(无栅栏)和 LOCK XCHG
    3. LOCK XADD ( 0 ) 和 STORE (无栅栏)

    否则仍有可能重新订购。

    根据@LWimsey的评论,我在这里犯了一个错误,如果 和LOAD都是STOREmemory_order_seq_cst则没有重新排序。Alex 可能指出使用非原子或非 SC 的情况。

  4. std::atomic_thread_fence(memory_order_seq_cst)总是产生一个完整的屏障

    这是根据Alex的回答。所以我总是可以替换asm volatile("mfence" ::: "memory")std::atomic_thread_fence(memory_order_seq_cst)

    这对我来说很奇怪,因为memory_order_seq_cst原子函数和栅栏函数之间的用法似乎有很大不同。

现在我在MSVC 2015的标准库的头文件中找到这段代码,它实现了std::atomic_thread_fence

inline void _Atomic_thread_fence(memory_order _Order)
    {   /* …
Run Code Online (Sandbox Code Playgroud)

c++ x86 memory-barriers stdatomic

4
推荐指数
1
解决办法
2212
查看次数

C11 独立内存屏障 LoadLoad StoreStore LoadStore StoreLoad

我想在原子和非原子操作之间使用独立的内存屏障(我认为无论如何它都不重要)。我想我了解存储屏障和加载屏障的含义以及 4 种可能的内存重新排序;LoadLoad, StoreStore, LoadStore, StoreLoad.

但是,我总是发现获取/释放概念令人困惑。因为在阅读文档时,acquire 不仅说到loads,还说到stores,而release 不仅说到stores,还说到loads。另一方面,普通负载障碍仅为您提供负载保证,而普通商店障碍仅为您提供商店保证。

我的问题如下。在 C11/C++11 中,将独立atomic_thread_fence(memory_order_acquire)视为负载屏障(防止LoadLoad重新排序)和atomic_thread_fence(memory_order_release)存储屏障(防止StoreStore重新排序)是否安全?

如果以上是正确的,我可以用什么来防止LoadStoreStoreLoad重新排序?

当然,我对可移植性感兴趣,我不在乎上述在特定平台上产生什么。

c c++ memory-model memory-barriers stdatomic

2
推荐指数
1
解决办法
368
查看次数