根据标准有以下示例
#include <atomic>
#include <cassert>
#include <thread>
std::atomic<bool> x = {false};
std::atomic<bool> y = {false};
std::atomic<int> z = {0};
void write_x()
{
x.store(true, std::memory_order_seq_cst);
}
void write_y()
{
y.store(true, std::memory_order_seq_cst);
}
void read_x_then_y()
{
while (!x.load(std::memory_order_seq_cst))
;
if (y.load(std::memory_order_seq_cst))
++z;
}
void read_y_then_x()
{
while (!y.load(std::memory_order_seq_cst))
;
if (x.load(std::memory_order_seq_cst))
++z;
}
int main()
{
std::thread a(write_x);
std::thread b(write_y);
std::thread c(read_x_then_y);
std::thread d(read_y_then_x);
a.join(); b.join(); c.join(); d.join();
assert(z.load() != 0); // will never happen
}
基于 x/y 的标准加载发生在 x/y 存储之后。因此,没有断言被触发 如果上面的代码改成如下
#include <atomic>
#include <cassert>
#include <thread>
std::atomic<bool> x = {false};
std::atomic<bool> y = {false};
std::atomic<int> z = {0};
void write_x()
{
x.store(true, std::memory_order_release);
}
void write_y()
{
y.store(true, std::memory_order_release);
}
void read_x_then_y()
{
while (!x.load(std::memory_order_acquire))
;
if (y.load(std::memory_order_acquire))
++z;
}
void read_y_then_x()
{
while (!y.load(std::memory_order_acquire))
;
if (x.load(std::memory_order_acquire))
++z;
}
int main()
{
std::thread a(write_x);
std::thread b(write_y);
std::thread c(read_x_then_y);
std::thread d(read_y_then_x);
a.join(); b.join(); c.join(); d.join();
assert(z.load() != 0); // will never happen
}
然后断言被触发。 但我的问题是其他线程何时知道存储值 x/y ? 根据标准有以下声明
从线程 A 的角度来看,在原子存储之前发生的所有内存写入(包括非原子和宽松原子)在线程 B 中都成为可见的副作用。也就是说,一旦原子加载完成,线程 B保证看到线程 A 写入内存的所有内容。仅当 B 实际上返回 A 存储的值或释放序列中稍后的值时,此承诺才成立。
线程写入值x。当线程 c 或 d 加载变量 x 时,线程 B 是否知道新值 x? 触发断言的竞争条件到底是什么?
基于 x/y 的标准加载发生在 x/y 存储之后。因此,没有断言被触发
更准确地说,顺序一致操作的单一总修改顺序意味着存储 x、存储 y 和加载的操作按some 顺序发生。
特别是,x 的存储或 y 的存储在此修改顺序中首先发生。假设它是 x。然后,在等待 y 为 true 的线程中,之后必须为 x 加载 true。
触发断言的竞争条件到底是什么?
没有订单。 read_x_then_y 可能加载 x true,然后 y false,read_y_then_x 可能加载 y true,然后 x false。