[英]Mixing Relaxed and Release-Acquire Memory Orders
Consider std::atomic<int> x(0)
.考虑
std::atomic<int> x(0)
。 If I understand correctly, std::memory_order_relaxed
guarantees only that the operation happens atomically, but provides no guarantees of synchronization.如果我理解正确,
std::memory_order_relaxed
仅保证操作以原子方式发生,但不提供同步保证。 So x.fetch_add(1, std::memory_order_relaxed)
1000 times from 2 threads will have an end result of 2000 always.因此
x.fetch_add(1, std::memory_order_relaxed)
来自 2 个线程的x.fetch_add(1, std::memory_order_relaxed)
1000 次将始终具有 2000 的最终结果。 However, the returned value of any one of those calls is not guaranteed to reflect the true current value (eg the 2000th increment could return 1700 as the previous value).但是,这些调用中的任何一个的返回值都不能保证反映真实的当前值(例如,第 2000 次增量可能返回 1700 作为前一个值)。
But - and here's my confusion - given that those increments are happening in parallel, what would x.load(std::memory_order_acquire)
return?但是 - 这就是我的困惑 - 鉴于这些增量是并行发生的,
x.load(std::memory_order_acquire)
返回什么? Or x.fetch_add(1, std::memory_order_acq_rel)
?还是
x.fetch_add(1, std::memory_order_acq_rel)
? Do these return the true current value or do they have the same problem of out-of-date answers that relaxed ordering has due to the relaxed increments?这些是否返回真实的当前值,或者它们是否具有由于宽松的增量而导致的宽松排序所具有的过时答案的相同问题?
As far as I can tell, the standard only guarantees that releasing to an acquire (on the same variable) synchronizes and thus gives the true current value.据我所知,该标准仅保证释放到获取(在同一变量上)同步并因此给出真实的当前值。 So how can relaxed mix in with typical acquire-release semantics?
那么如何轻松混合典型的获取-释放语义呢?
For instance, I've heard std::shared_ptr
's reference count is incremented in relaxed order and decremented in acq_rel order because it needs to ensure it has the true value in order to only delete the object once.例如,我听说
std::shared_ptr
的引用计数以宽松的顺序递增并以 acq_rel 的顺序递减,因为它需要确保它具有真值以便只删除一次对象。 Because of this I'm tempted to think they would give the true current value, but I can't seem to find any standardese to back it up.因此,我很想认为他们会给出真实的当前值,但我似乎找不到任何标准来支持它。
ISO C++ guarantees that a modification order exists for every atomic object separately. ISO C++ 保证对每个原子对象分别存在一个修改顺序。
With seq_cst there's guaranteed to be a global order where all threads can agree on a
changing before b
or something.随着seq_cst还有的保证是一个全球性的秩序,所有线程能够同意
a
之前,改变b
或东西。 But for a single object, a modification order is guaranteed to exist even if some operations are relaxed.但是对于单个对象,即使放宽了一些操作,也保证存在修改顺序。
The return values you from relaxed fetch_add
define / record what the modification order was.您从轻松的
fetch_add
返回值定义/记录修改顺序是什么。 The 2000th increment returns 2000
by definition , that's how you know it was the 2000th.根据定义,第 2000 次增量返回
2000
,这就是您知道它是第 2000 次的方式。
As far as I can tell, the standard only guarantees that releasing to an acquire (on the same variable) synchronizes and thus gives the true current value.
据我所知,该标准仅保证释放到获取(在同一变量上)同步并因此给出真实的当前值。
Synchronizes-with is only necessary if you care about reading other values, eg one thread stores to a non-atomic array, then does a release-store like data_ready = 1;
只有当您关心读取其他值时才需要同步,例如,一个线程存储到非原子数组,然后执行像
data_ready = 1;
这样的释放存储data_ready = 1;
. . For a reader to safely read data from the array, they need to see
data_ready != 0
with an acquire load, which means they can also see the effects of all earlier assignments in the thread that did the release-store.为了让读者安全地从数组中读取数据,他们需要在获取加载时看到
data_ready != 0
,这意味着他们还可以看到执行释放存储的线程中所有早期分配的效果。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.