是否存在这样的情况:我们希望将一个带有memory_order_acquire
的原子加载到带有memory_order_release
的同一个原子上,而不进行相应的存储?
例如,如果我有这样一段代码:
std::atomic<uint64_t> state;
std::atomic<uint64_t> count;
// Thread 1
while (true)
{
auto expected = state.load(memory_order_relaxed);
auto desired = get_desired(expected);
if (state.compare_exchange_weak(expected, desired, memory_order_relaxed, memory_order_relaxed) { <----- (A)
count.fetch_add(1, memory_order_relaxed); <---- (B)
break;
}
}
// Thread 2
auto state = state.load(memory_order_acquire); <----- (C)
auto count = count.load(memory_order_relaxed); <----- (D)
线程2中的memory_order_acquire
应该防止count
的加载在state
的加载之前移动,但是由于我们在其他地方都使用memory_order_relaxed
,我说线程2可能会看到count
的更新值,该值可能比state
更新,即看到(B)才能看到(A)中compare_exchange
的效果?
如果我想让线程2在(C)中加载(A)时始终可以看到它的效果,那么我是否应该将(B)更改为memory_order_release
,在(D)中使用memory_order_acquire
,并颠倒(C)和(D)的顺序?
1条答案
按热度按时间kokeuurv1#
线程2中的
memory_order_acquire
应防止count
的加载在state
的加载之前移动不可以。C++中的原子内存排序并不是从防止某些操作彼此重新排序的Angular 来定义的。相反,它是从要求某些副作用在某些点可见的Angular 来定义的。特别是,
如果只有获取加载而没有释放存储,那么就没有这样的排序保证。
我说线程2可能[...]在看到来自(A)的
compare_exchange
的效果之前看到(B)的效果,对吗?是的。
如果我想让线程2在(C)中加载(A)时始终可以看到它的效果,那么我是否应该将(B)更改为
memory_order_release
,在(D)中使用memory_order_acquire
,并颠倒(C)和(D)的顺序?是的。假设我没有理解错,在您执行了所描述的转换序列之后,我们将得到
state
到compare_exchange_weak
的松弛存储,随后是到count
到fetch_add
的释放存储count
获取负载,然后从state
释放负载假设来自
count
的acquire-load读取线程1存储的值,则线程2中来自state
的松弛加载必须观察线程1存储的值 * 或更晚的值 *。