繁体   English   中英

具有 memory_order_relaxed 的存储是否可能永远不会到达其他线程?

[英]Is it possible that a store with memory_order_relaxed never reaches other threads?

假设我有一个线程A写入一个atomic_int x = 0; , 使用x.store(1, std::memory_order_relaxed); . 如果没有任何其他同步方法,使用x.load(std::memory_order_relaxed);其他线程需要多长时间才能看到这一点x.load(std::memory_order_relaxed); ? 鉴于标准给出的 C/C++ 内存模型的当前定义,写入x的值是否可能完全保持线程本地?

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

编辑

我联系了 Mark Ba​​tty(在数学上验证并随后修复 C++ 内存模型要求背后的大脑)。 本来是关于别的(后来证明是 cppmem 和他的论文中的一个已知错误;所以幸运的是我没有完全自欺欺人,也借此机会问他这个问题;他的回答是:

Q:理论上可以这样的存储[memory_order_relaxed without (any following) release operation]永远不会到达其他线程吗?
马克:理论上,是的,但我认为没有观察到。
问:换句话说,除非你将它们与一些释放操作(并在另一个线程上获取)结合起来,假设你想让另一个线程看到它,否则宽松存储没有任何意义吗?
马克:他们的几乎所有用例都使用发布和获取,是的。

这就是标准对此事的全部看法,我相信:

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

在实践中

如果没有任何其他同步方法,使用x.load(std::memory_order_relaxed);其他线程需要多长时间才能看到这一点x.load(std::memory_order_relaxed); ?

没时间。 这是一个正常的写入,它进入存储缓冲区,因此它将在不到眨眼的时间内在 L1d 缓存中可用。 但这只是运行汇编指令

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

理论上

Q:理论上这样的存储[ memory_order_relaxed without (any following) release operation]永远不会到达其他线程吗?

马克:理论上,是的,

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

为什么不将这些重新排序并延迟很长时间? (久到在实践中似乎是永恒的)

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

如果一个虚构的、特别反常的实现想要延迟原子操作的可见性,为什么它只对宽松的操作这样做呢? 它可以很好地完成所有原子操作。

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

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

这是标准在 29.3.12 中所说的:

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

不能保证一个store会在另一个线程中可见,没有保证的时间,也没有与内存顺序的正式关系。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM