我一直在关注“C ++并发操作”一书中的示例,以更好地理解获取 - 发布模型,但我有一些问题:
std::atomic<int> data[3];
std::atomic<bool> sinc1(false), sinc2(false);
void thread_1() {
data[0].store(1,std::memory_order_relaxed);
data[1].store(2,std::memory_order_relaxed);
data[2].store(3,std::memory_order_relaxed);
sinc1.store(true,std::memory_order_release);
}
void thread_2() {
while(!sinc1.load(std::memory_order_acquire))
sinc2.store(true,std::memory_order_release);
}
void thread_3() {
while(!sinc2.load(std::memory_order_acquire))
assert(data[0].load(std::memory_order_relaxed)==1);
std::cout << data[0] << std::endl;
assert(data[1].load(std::memory_order_relaxed)==2);
std::cout << data[1] << std::endl;
assert(data[2].load(std::memory_order_relaxed)==3);
std::cout << data[2] << std::endl;
}
int main() {
std::thread t1(thread_1);
std::thread t2(thread_2);
std::thread t3(thread_3);
t1.join();
t2.join();
t3.join();
return 0;
}
现在,sinc1中的商店发生了 - 在thread_2中的sinc1加载之前,在sinc2中的商店之前进行了排序。 sinc2中的存储形成另一个释放 - 获取对,在thread_3中加载sinc2,这在数据加载之前发生。 由于转换,thread_1中的数据存储发生在thread_3中的数据加载之前。 “断言不应该开火。
相反,当我运行它时,我会得到我所期望的,但有时候:
Assertion failed: (data[0].load(std::memory_order_relaxed)==1)....
我有两个问题:
我错过了什么吗?
当它没有失败时我得到了这些输出:
:
1 2 3
或
0 1 2
sync1上的release-acquire内存模型是否应该在商店数据上给出一定的内存顺序?
如果我想遵循严格的命令,为什么我会放松。
我知道我可以使用放松和一起释放达到某个顺序。但显然它不起作用
0 1 2
有人可以向我澄清这些观点吗?
谢谢。
答案 0 :(得分:0)
memory_order_relaxed 轻松排序:没有同步 或排序约束,此操作只需要原子性。
C ++ 14对订购有一些进一步的限制,这里不适用。
void thread_1() {
data[0].store(1,std::memory_order_relaxed);
data[1].store(2,std::memory_order_relaxed);
data[2].store(3,std::memory_order_relaxed);
---上下文切换---
这些现在可以被&#34;随机&#34;中的其他线程看到。因为他们只保证原子操作。所以其他线程可以看到0 / 1,0 / 2,0 / 0的任意组合,例如0,2,0但不是0,1,2 ......除非数据在开始之前具有这些值,所以将第一行更改为
std::atomic<int> data[3] = { -1,-1,-1 }; // lets make sure we know what we have
在thread_1
完成
sinc1.store(true,std::memory_order_release);
}
以前对内存的所有写操作都必须完成。
memory_order_release 具有此内存顺序的商店操作 执行释放操作:事先写入其他内存位置 对消费或获取的线程变得可见 同一地点。
幸运的是,thread_2
在同一地点进行了获取
void thread_2() {
while(!sinc1.load(std::memory_order_acquire)) <----------- bug here missing ;
sinc2.store(true,std::memory_order_release);
}
所以虽然!sinc1我们将sinc2设置为true,但我猜这不是你想要的。 为了避免这样的问题,总是放置{}。
答案 1 :(得分:0)
问题似乎是你的代码在while循环之后错过了;
。
但我不同意你的看法:在这两个地方使用分号,断言必须永远不会触发,代码将始终打印1 2 3
。