您能否将具有更严格内存排序的原子加载存储拆分为单独的宽松加载存储以及内存屏障指令?

Sou*_*a B 5 c++ multithreading synchronization atomic memory-barriers

下面是用于跨线程数据同步的获取-释放语义的简单示例。

// thread 1                                     // thread 2
data = 100;
flag.store(true, std::memory_order_release);
                                                while(!flag.load(std::memory_order_acquire));
                                                assert(data == 100);
Run Code Online (Sandbox Code Playgroud)

据我了解,这准确地表明了获取-释放内存顺序的使用,并且程序将按预期工作。

但如果我使用独立屏障会怎样?

// thread 1                                     // thread 2
data = 100;
std::atomic_thread_fence(std::memory_order_release);
flag.store(true, std::memory_order_relaxed);
                                                while(!flag.load(std::memory_order_relaxed))
                                                    std::atomic_thread_fence(std::memory_order_acquire);
                                                assert(data == 100);
Run Code Online (Sandbox Code Playgroud)

我一直认为这与第一个例子完全相同

但今天我在 CppCon 上观看了 Herb Sutter 的演讲(C++ and Beyond 2012:Herb Sutter - 原子武器)。在视频中的1:07:10 ,他举了一个例子来说明独立围栏的效果并不理想。看完后我很困惑。

例子是这样的:

   // thread 1                                     // thread 2
   widget *temp = new widget();
XX mb();  XXXXXXXXXXXXXXXXXXXXX  // a
   global = temp;
                                                   temp2 = global;
                                                XX mb();  XXXXXXXXXXXXXXXXXXXXX  // b
                                                   temp2->do_something();
                                                   temp2 = global;
                                                XX mb();  XXXXXXXXXXXXXXXXXXXXX
                                                   temp2->do_something_else();
Run Code Online (Sandbox Code Playgroud)

他说,在 a 和 b 处,您需要一个完整的屏障,而不仅仅是释放和获取,因为它们与任何特定的存储或负载无关。此外,他表示,独立的获取和释放障碍没有任何意义。它是否正确?(为了简单起见,假设对global的读取和写入是不可分割的,即global永远不包含撕裂值)。

为什么这不起作用?

   // thread 1                                     // thread 2
   widget *temp = new widget();
XX release();  XXXXXXXXXXXXXXXX  // a
   global = temp;
                                                   temp2 = global;
                                                XX acquire();  XXXXXXXXXXXXXXXX  // b
                                                   temp2->do_something();
                                                   temp2 = global;
                                                XX acquire();  XXXXXXXXXXXXXXXX
                                                   temp2->do_something_else();
Run Code Online (Sandbox Code Playgroud)