关注公众号获取更多信息:

若线程 A 中的一个原子存储带标签 memory_order_release ,而线程 B 中来自同一变量的原子加载带标签 memory_order_acquire ,则从线程 A 的视角先发生于原子存储的所有内存写入(非原子及宽松原子的),在线程 B 中成为可见副效应,即一旦原子加载完成,则保证线程 B 能观察到线程 A 写入内存的所有内容。
同步仅建立在释放和获得同一原子对象的线程之间。其他线程可能看到与被同步线程的一者或两者相异的内存访问顺序。
在强顺序系统( x86 、 SPARC TSO 、 IBM 主框架)上,释放获得顺序对于多数操作是自动进行的。无需为此同步模式添加额外的 CPU 指令,只有某些编译器优化受影响(例如,编译器被禁止将非原子存储移到原子存储-释放后,或将非原子加载移到原子加载-获得前)。在弱顺序系统( ARM 、 Itanium 、 Power PC )上,必须使用特别的 CPU 加载或内存栅栏指令。
互斥锁(例如 std::mutex 或原子自旋锁)是释放获得同步的例子:线程 A 释放锁而线程 B 获得它时,发生于线程 A 环境的临界区(释放之前)中的所有事件,必须对于执行同一临界区的线程 B (获得之后)可见。
#include <thread>#include <atomic>#include <cassert>#include <string>std::atomic<std::string*> ptr;int data;void producer(){std::string* p = new std::string("Hello");data = 42;ptr.store(p, std::memory_order_release);}void consumer(){std::string* p2;while (!(p2 = ptr.load(std::memory_order_acquire)));assert(*p2 == "Hello"); // 绝无问题assert(data == 42); // 绝无问题}int main(){std::thread t1(producer);std::thread t2(consumer);t1.join(); t2.join();}
下例演示三个线程间传递性的释放获得顺序
#include <thread>#include <atomic>#include <cassert>#include <vector>std::vector<int> data;std::atomic<int> flag = {0};void thread_1(){data.push_back(42);flag.store(1, std::memory_order_release);}void thread_2(){int expected=1;while (!flag.compare_exchange_strong(expected, 2, std::memory_order_acq_rel)) {expected = 1;}}void thread_3(){while (flag.load(std::memory_order_acquire) < 2);assert(data.at(0) == 42); // 决不出错}int main(){std::thread a(thread_1);std::thread b(thread_2);std::thread c(thread_3);a.join(); b.join(); c.join();}
本文深入探讨了C++中基于原子操作的release-acquire同步机制,解释了如何通过内存顺序保证线程间的可见性。示例展示了在多线程环境下,如何利用std::atomic保证数据一致性,确保线程A的修改对线程B可见。同时,文章提到了不同处理器架构(如x86与ARM)对此的支持情况,并提供了相关代码示例。
释放获得顺序 内存模型(四)&spm=1001.2101.3001.5002&articleId=116881265&d=1&t=3&u=09fc842a6b904c44ae40b645e4bf9239)
6079

被折叠的 条评论
为什么被折叠?



