您能解释一下为什么断言可以触发吗?我无法理解下面的解释。
if(y.load...
和 if(x.load...
都使用 std::memory_order_acquire
。这还不够吗?书中写道,我们需要 seq_cst 才能触发断言not。 seq_cst 这里如何改进?
#include <atomic>
#include <thread>
#include <assert.h>
std::atomic<bool> x,y;
std::atomic<int> z;
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()
{
x=false;
y=false;
z=0;
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);
}
在这种情况下,断言可以触发(就像在宽松排序的情况下一样),因为 x 的负载和 y 的负载都可能读取为 false。 x 和 y 是由不同的线程写入的,因此每种情况下从释放到获取的顺序没有顺序 对其他线程中的操作的影响。
参见 https://en.cppreference.com/w/cpp/atomic/memory_order
具有此内存顺序的加载操作执行获取操作,存储执行释放操作,读取-修改-写入执行获取操作和释放操作,并且存在所有线程观察到的单个总顺序所有修改均按相同顺序进行(请参阅下面的顺序一致排序)。memory_order_seq_cst
如果没有
memory_order_seq_cst
,不同的线程可以看到原子操作以不同的顺序发生。 read_x_then_y
可以看到:
x = true;
y = true;
虽然
read_y_then_x
可以看到:
y = true;
x = true;
在这种情况下,如果两个线程都测试两个集合之间的第二个变量,则两个线程都不会设置
z
。原子写入可能发生在不同的 CPU 核心上,然后核心必须就写入进行相互通信,如果没有 memory_order_seq_cst
,他们不一定会费心去付出额外的努力来确保所有核心具有相同的视图写入发生的顺序。