我正在考虑原子变量是否可以在获取-释放对中加载旧值。假设我们有原子变量 x,我们用释放语义存储该变量,然后用获取语义加载它,理论上可以读取旧值吗?
std::atomic<int> x = 0;
void thread_1()
{
x.store(1, std::memory_order_release);
}
void thread_2()
{
assert(x.load(std::memory_order_acquire) != 0);
}
如果函数线程 1 在线程 2 加载 x 时完成(因此存储了新值),线程 2 是否可以从 x 加载旧值?换句话说,如果在加载之前完成了对 x 的实际存储,那么断言是否可以触发?
据我从互联网上的文章中了解到,这是可能的,但我不明白为什么。store to x 生成的内存栅栏保证清空存储缓冲区,而从 x 加载时获取内存栅栏保证使缓存行无效,因此它必须读取最新值。
添加
这是否意味着获取释放本身没有任何强制排序?只有在发布之前完成的任何事情都会在发布之前发生,而在获取之后完成的所有事情都会在它之后发生,因此获取-发布对强制对其他操作进行排序(为什么??)。我做对了吗?这是否意味着在下面的代码中断言保证不会触发
std::atomic<int> x = 0;
std::atomic<int> y = 0;
void thread_1()
{
y.store(1, std::memory_order_relaxed);
x.store(1, std::memory_order_release);
}
void thread_2()
{
x.load(std::memory_order_acquire);
assert(y.load(std::memory_order_relaxed) != 0);
}
当然,如果线程 1 已经完成了商店。如果我们用 while (x.load() == 0) 替换 x.load,这将 100% 有效,但我不知道是什么原因导致它起作用。
如果我用下面的代码替换代码怎么办
std::atomic<int> x = 0;
void thread_1()
{
x.exchange(1, std::memory_order_acq_rel);
}
void thread_2()
{
assert(x.exchange(0, std::memory_order_acq_rel) != 0);
}
它有什么改变吗?
谢谢。