提问人:Carlo Wood 提问时间:5/3/2017 最后编辑:JonasCarlo Wood 更新时间:12/13/2019 访问量:1211
有没有可能具有memory_order_relaxed的存储永远不会到达其他线程?
Is it possible that a store with memory_order_relaxed never reaches other threads?
问:
假设我有一个线程 A,它使用 写入 。如果没有任何其他同步方法,其他线程需要多长时间才能看到这一点,使用 ?考虑到标准给出的 C/C++ 内存模型的当前定义,写入的值是否有可能完全保持线程本地?atomic_int x = 0;
x.store(1, std::memory_order_relaxed);
x.load(std::memory_order_relaxed);
x
我手头的实际情况是线程 B 经常读取 an 以检查它是否必须退出;显然,我不介意在线程 B 看到atomic_bool设置之前调用 join(),也不介意线程 B 在调用 join() 之前已经看到更改并退出执行。但我想知道:在两边使用,是否可以“永远”调用 join() 并阻止,因为更改永远不会传播到线程 B?atomic_bool
memory_order_relaxed
编辑
我联系了Mark Batty(数学验证并随后修复C++内存模型需求的大脑)。本来是关于别的东西(原来是cppmem和他的论文中一个已知的bug;所以幸运的是我没有完全自欺欺人,并借此机会也问了他这个问题;他的回答是:
问:从理论上讲,这样的存储 [没有(任何后续)释放操作的 memory_order_relaxed] 永远不会到达另一个线程吗?
Mark:从理论上讲,是的,但我认为没有观察到这一点。
问:换句话说,休闲商店没有意义 除非您将它们与某些发布操作(和 在另一个线程上获取),假设您希望另一个线程 看到了吗?
Mark:几乎所有的用例都使用发布和获取,是的。
答:
这就是关于此事的所有标准,我相信:
[介绍.多线程]/25实现应确保原子或同步操作分配的最后一个值(按修改顺序)在有限的时间内对所有其他线程可见。
评论
这是标准在 29.3.12 中所说的:
实现应在合理的时间内使原子存储对原子负载可见。
不能保证 a 将在另一个线程中可见,没有保证的时序,并且与内存顺序没有正式的关系。store
当然,在每个常规架构上,a 都会变得可见,但在不支持缓存一致性的罕见平台上,它可能永远不会对 .
在这种情况下,您必须执行原子读取-修改-写入操作才能获取修改顺序中的最新值。store
load
评论
atomic
acquire/release
atomic
atomic
在实践中
如果没有任何其他同步方法,需要多长时间 在其他线程可以看到这一点之前,使用 ?
x.load(std::memory_order_relaxed);
没时间了。这是一个正常的写入,它进入存储缓冲区,因此它将在不到眨眼的时间内在 L1d 缓存中可用。但这只是在运行汇编指令时。
编译器可以对指令进行重新排序,但是没有一个合理的编译器会在任意长的循环中对原子操作进行重新排序。
理论上
问:从理论上讲,这样的商店[没有(任何后续)发布操作]永远不会到达另一个 线?
memory_order_relaxed
Mark:理论上,是的,
你应该问他,如果重新添加“以下发布围栏”会发生什么。或者使用原子存储释放操作。
为什么不重新订购这些并延迟时间呢?(如此之长,以至于在实践中似乎是永恒的)
写入 x 的值是否有可能完全保持线程本地 鉴于 C/C++ 内存模型的当前定义, 标准给?
如果一个虚构的、特别反常的实现想要延迟原子操作的可见性,为什么它只对宽松的操作这样做呢?它完全可以用于所有原子操作。
或者永远不要运行一些线程。
或者将一些线程运行得太慢,以至于您会认为它们没有运行。
评论