对不同线程中同一位置的两次轻松写入是否总是以相同的顺序被其他线程看到
Will two relaxed writes to the same location in different threads always be seen in the same order by other threads?
在 x86 架构上,存储到同一内存位置具有总顺序,例如,请看此视频。C++11 内存模型中有哪些保证?
更准确地说,在
-- Initially --
std::atomic<int> x{0};
-- Thread 1 --
x.store(1, std::memory_order_release);
-- Thread 2 --
x.store(2, std::memory_order_release);
-- Thread 3 --
int r1 = x.load(std::memory_order_acquire);
int r2 = x.load(std::memory_order_acquire);
-- Thread 4 --
int r3 = x.load(std::memory_order_acquire);
int r4 = x.load(std::memory_order_acquire);
结果r1==1, r2==2, r3==2, r4==1
是否被允许(在 x86 以外的某些体系结构上(?如果我用std::memory_order_relaxed
替换所有memory_order
怎么办?
不,这样的结果是不允许的。 §1.10 [intro.multithread]/p8, 18 (引用N3936/C++14;N3337/C++11的第6段和第16段中可以找到相同的文本(:
8 对特定原子对象M的所有修改都发生在某些 特定的总阶,称为M的修改阶。
18 如果原子对象 M 的值计算 A 发生在 M 的值计算 B,A 从副作用 X 中获取其值 在 M 上,则 B 计算的值应为 X 或 M 上的副作用 Y 存储的值,其中 Y 在 X 之后 M. [ 注意:此要求称为 读读连贯性。—尾注 ]
在你的代码中有两个副作用,到 p8 时,它们以某种特定的总顺序出现。在线程 3 中,计算要存储在r1
中的值的值计算发生在 r2
之前,因此给定r1 == 1
和r2 == 2
我们知道线程 1 执行的存储先于线程 2 执行的存储,修改顺序为 x
。在这种情况下,Thread 4
无法在不违反p18的情况下观察r3 == 2, r4 == 1
。这与使用memory_order
无关。
p21 中有一个相关的注释(N3337 中的 p19(:
[注:上述四项一致性要求有效 不允许编译器将原子操作重新排序为单个对象, 即使这两个操作都是松弛负载。这有效地使 大多数硬件提供的缓存一致性保证可供C++ 原子操作。—尾注 ]
根据 C++11 [intro.multithread]/6:"对特定原子对象的所有修改M
以某种特定的总顺序发生,称为M
的修改顺序。因此,特定线程对原子对象的读取永远不会看到比线程已经观察到的值"旧"的值。请注意,此处没有提到内存排序,因此此属性适用于所有内存排序 - seq_cst
到 relaxed
。
在OP中给出的示例中,x
的修改顺序可以是(0,1,2)
也可以是(0,2,1)
。在该修改顺序中观察到给定值的线程以后无法观察到较早的值。结果r1==1, r2==2
暗示x
的修改阶是(0,1,2)
的,但r3==2, r4==1
暗示它是(0,2,1)
的,这是一个矛盾。因此,在符合 C++11 的实现上不可能产生该结果。
鉴于 C++11 规则绝对不允许这样做,这里有一种更定性/直观的方法来理解它:
如果没有其他商店可以x
,最终所有读者都会同意它的价值。 (即两家商店中的一家排名第二(。
如果不同的线程有可能不同意顺序,那么他们要么永久/长期不同意该值,要么一个线程可以看到值第三次额外更改(幻影存储(。
幸运的是,C++11不允许这两种可能性。
- 如何检查线程是否锁定
- 并发/多线程:是否可以以这种方式生成相同的输出?
- 当我在C++中调用 struce 的只读静态成员时,线程是否安全
- 检查分离的线程是否还活着?
- 将正常函数的工作分配给多个线程是否安全
- 最大线程数 - 如何确定C++线程是否并行运行?
- 如何确定其他线程是否正在运行?
- 线程是否真的在调用 std::future::get() 后启动
- 如何知道分离的STD ::线程是否完成了执行
- 通知线程是否始终需要在修改期间锁定共享数据
- 只写到共享 std::unordered_map 线程是否安全
- 检查线程是否在 c++11 中完成
- C++ 互斥 - 检查另一个线程是否正在等待
- 提升::作用域的线程是否自动分离
- 以下单例实现线程是否安全?
- 确定线程是否已退出
- 我的不同线程是否会看到更新后的shared_ptr对象
- 使用操作当前对象的线程是否安全
- 此同步对象实现线程是否安全
- 线程是否共享一些类字段