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

之前讲的都是理论相关的,下面详细讲一下我们现实中会使用到的内存模型。今天是最简单也是最宽松的内存模型----memory_order_relaxed
带标签 memory_order_relaxed 的原子操作无同步操作;它们不会在同时的内存访问间强加顺序。它们只保证原子性和修改顺序一致性。
例如,
对于最初为零的 x 和 y ,// 线程 1 :r1 = y.load(std::memory_order_relaxed); // Ax.store(r1, std::memory_order_relaxed); // B// 线程 2 :r2 = x.load(std::memory_order_relaxed); // Cy.store(42, std::memory_order_relaxed); // D
允许产生结果 r1 == 42 && r2 == 42 ,因为即使线程 1 中 A 先序于 B 且线程 2 中 C 先序于 D ,却没有制约避免 y 的修改顺序中 D 先出现于 A ,而 x 的修改顺序中 B 先出现于 C 。D 在 y 上的副效应,可能可见于线程 1 中的加载 A ,同时 B 在 x 上的副效应,可能可见于线程 2 中的加载 C 。
|
即使使用宽松内存模型,也不允许“无中生有”的值循环地依赖于其各自的计算,例如,对于最初为零的 x 和 y , // 线程1: r1 = x.load(std::memory_order_relaxed); if (r1 == 42) y.store(r1, std::memory_order_relaxed); // 线程2: r2 = y.load(memory_order_relaxed); if (r2 == 42) x.store(42, std::memory_order_relaxed); 不允许产生结果 r1 == 42 && r2 == 42 ,因为存储 42 于 y 只在存储 42 于 x 后有可能,这又循环依赖于存储 42 于 y 。注意 C++14 前规范曾在技术上允许,但不推荐实现者如此实现。 | (C++14 起) |
宽松内存顺序的典型使用是计数器自增,例如 std::shared_ptr 的引用计数器,因为这只要求原子性,但不要求顺序或同步(注意 std::shared_ptr 计数器自减要求与析构函数进行获得释放同步)
下面举个例子:
#include <vector>#include <iostream>#include <thread>#include <atomic>std::atomic<int> cnt = {0};void f(){for (int n = 0; n < 1000; ++n) {cnt.fetch_add(1, std::memory_order_relaxed);}}int main(){std::vector<std::thread> v;for (int n = 0; n < 10; ++n) {v.emplace_back(f);}for (auto& t : v) {t.join();}std::cout << "Final counter value is " << cnt << '\n';}
输出:
Final counter value is 10000
那么在什么情景下使用memory_order_relaxed呢?
由于Relaxed ordering 仅仅保证load()和store()是原子操作,除此之外,不提供任何跨线程的同步。
如果某个操作只要求是原子操作,除此之外,不需要其它同步的保障,就可以使用 Relaxed ordering。程序计数器是一种典型的应用场景:
#include <cassert>#include <vector>#include <iostream>#include <thread>#include <atomic>std::atomic<int> cnt = {0};void f(){for (int n = 0; n < 1000; ++n) {cnt.fetch_add(1, std::memory_order_relaxed);}}int main(){std::vector<std::thread> v;for (int n = 0; n < 10; ++n) {v.emplace_back(f);}for (auto& t : v) {t.join();}assert(cnt == 10000); // never failedreturn 0;}
本文深入解析了C++中的memory_order_relaxed内存模型,展示了它如何在不提供同步保障的前提下支持原子操作,如计数器自增。通过实例说明了其应用场景,以及何时选择这种宽松的内存顺序。
1万+

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



