带有memory_order_relaxed的商店是否可能永远不会到达其他线程?

时间:2017-05-03 02:15:40

标签: c++ c++11 memory-barriers relaxed-atomics

假设我有一个使用atomic_int x = 0;写入x.store(1, std::memory_order_relaxed);的帖子 A 。在没有任何其他同步方法的情况下,使用x.load(std::memory_order_relaxed);,其他线程可以在多长时间内看到这一点?在给定标准给出的C / C ++内存模型的当前定义的情况下,写入x的值是否可能完全保持线程局部性?

我手边的实际案例是线程 B 经常读取atomic_bool以检查是否必须退出;另一个线程,在某些时候,将 true 写入此bool,然后在线程B上调用join()。很明显,我不介意在线程B甚至可以看到atomic_bool被设置之前调用join() ,在调用join()之前,线程B已经看到更改并退出执行,我也不介意。但我想知道:在双方使用memory_order_relaxed,是否可以调用join()并阻止"永远"因为改变永远不会传播到线程B?

修改

我联系了Mark Ba​​tty(数学验证并随后修复C ++内存模型要求的大脑)。最初是关于别的东西(原来是cppmem和他的论文中的一个已知的错误;幸运的是,我并没有完全愚弄自己,并借此机会向他询问这个问题;他的回答是:< / p>

  

问:从理论上讲,这样的商店[memory_order_relaxed没有(任何跟随)释放操作]永远不会到达另一个线程吗?
  马克:理论上,是的,但我认为没有观察到。
  问:换句话说,放松的商店是没有意义的   除非你把它们与一些释放操作结合起来(和   获取另一个线程),假设你想要另一个线程   看到了吗?   Mark:几乎所有的用例都使用release和acquire,是的。

3 个答案:

答案 0 :(得分:4)

这是关于此事的所有标准,我相信:

  

[intro.multithread]/25 实现应该确保原子或同步操作分配的最后一个值(按修改顺序)在有限的时间内对所有其他线程可见。< / p>

答案 1 :(得分:1)

这是标准在29.3.12中所说的内容:

  

实现应该使原子存储在合理的时间内对原子载荷可见。

无法保证store在另一个线程中可见,没有保证的时间,并且与内存顺序没有正式关系。

当然,在每个常规架构上,store 变得可见,但在不支持缓存一致性的罕见平台上,它可能永远不会被load看到。
在这种情况下,您必须进行原子读取 - 修改 - 写入操作以获取修改顺序中的最新值。

答案 2 :(得分:1)

在实践中

  

没有其他任何同步方法,需要多长时间   在其他线程可以看到之前,使用   x.load(std::memory_order_relaxed);

没有时间。这是正常的写操作,它会到达存储缓冲区,因此它可以在L1d高速缓存中使用,而不用花一秒钟的时间。但这只是何时运行汇编指令。

编译器可以对指令进行重新排序,但是没有合理的编译器会在任意长的循环上对原子操作进行重新排序。

理论上

  

问:从理论上讲,可以是这样的商店吗?[memory_order_relaxed   没有(任何以下)释放操作]永远不会到达另一个   线程?

     

Mark:理论上是,

您应该问他,如果重新添加“后续发布围栏”会发生什么情况。或使用原子存储释放操作。

为什么不重新安排这些订单并延迟很长的时间? (只要在实践中看起来像是永恒的)

  

写入x的值是否可能完全保持线程局部   给定C / C ++内存模型的当前定义,   标准给?

如果一个虚构的,尤其是 perverse 的实现想要延迟原子操作的可见性,为什么它只对放松的操作这样做呢?可以对所有原子操作都做到这一点。

或者永远不要运行一些线程。

或者运行某些线程的速度太慢,以至于您会认为它们没有运行。