我从以下位置获取了有关 std::memory_order_seq_cst 的示例:http://en.cppreference.com/w/cpp/atomic/memory_order http://en.cppreference.com/w/cpp/atomic/memory_order
#include <thread>
#include <atomic>
#include <cassert>
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
}
这个例子在问题中也提到了获取/释放与顺序一致的内存顺序 https://stackoverflow.com/questions/14861822/acquire-release-versus-sequentially-consistent-memory-order.
我的问题是线程 c 和线程 d 怎么可能看到不同的东西?如果可能的话,为什么下面这个简单的例子总是产生 z=3?例如,线程 b 可能会说“好吧,我看到 0,即使线程 a 已经完成,所以 z 再次变为 0+1”
#include <atomic>
#include <iostream>
std::atomic<int> z = {0};
void increment()
{
z.fetch_add(1, std::memory_order_relaxed);
}
int main()
{
std::thread a(increment);
std::thread b(increment);
std::thread c(increment);
a.join(); b.join(); c.join();
std::cout << z.load() << '\n';
}
因此,通过在评论中看到不同的内容,您的意思是线程 C 看到 x==1,y==0,线程 D 看到 x==0 和 y==1。这可以通过顺序一致性实现吗?
让我们假设这个全序(修改是这个符号化内存状态之间的转换):
{x==0,y==0} : S0
{x==1,y==0} : S1
{x==1,y==1} : S2
当我们说“看到”时,我们的意思是线程可能执行加载。两个加载不能在一个线程中同时执行。那么线程C怎么可能看到x==1then参见 y==0,线程 D 参见 x==0then看到 y==1 了吗?当内存处于状态 S1 时,线程 C 执行两次加载,线程 D 看到x
在状态S0,然后看y
在状态S2。
在您的示例代码中,发生的情况是线程 C 加载 x,然后加载 y,线程 D 重复加载 y,直到它为 true,然后加载 x。所以在y==1之后,可以保证x==1
按照这个总顺序。
正如 Minee 在其评论中所说,如果使用获取/释放内存顺序代替顺序一致性内存顺序,则不会有任何结果:获取/释放语义并不意味着任何总排序,而且没有发生在之前商店之间的关系x
和商店y
。所以断言z.load()!=0
可以开火。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)