这种获取-释放关系是如何运作的?

问题描述 投票:0回答:1

Rust Atomics and Locks中,或多或少建议使用以下代码来正确实现简化的

drop
Arc
特征:(代码是我的)

        unsafe {
            if 1 == (*self.inner).strong.fetch_sub(1, Release) {
                fence(Acquire);
                let box_ = Box::rom_raw(self.inner);
                drop(box_);
            }
        }

其中

(*self.inner).strong
AtomicUsize

所以这是我的问题:

我知道

acquire
将与前一个
release
(与写入加载值的线程)建立“发生之前/同步”关系。为了正确地设置
drop
的值,我们需要将每个
Arc
fetch_sub
一个接一个地链接起来。

我不明白这里是如何保证这一点的。如果我们

acquired
原子的值,替换 1,然后
release
d,所有这些都在一个操作中(基本上是
fetch_sub
AcqRel
排序或比较和交换循环),我会理解。

这里,我们只是在加载1的时候“获取”。我对在

Release
上使用
fetch_sub
的理解是,
fetch
部分是
relaxed
。基于这种理解,我对上述代码有两个问题:

1

这种情况不可能吗:

Thread A:
  load: 2 (t = 1)
  write 1 (t = ?)
Thread B:
  load: 2 (t = 1)
  write 1 (t = ?)

因此价值从未下降?我看不出

load
如何保证它对该值具有独占访问权限,这意味着它将始终按顺序加载。

2

我不是只在

1
的读取和下降之间建立了“发生之前”的关系吗?我认为这很好,因为如果我确实看到了 1,我就可以
 放弃,但是我如何保证看到 
1
并且不会在原子上发生数据竞争?

我怀疑我的误解来自原子/排序提供的保证,但是

multithreading rust atomic memory-barriers
1个回答
0
投票

对于原子数据来说,原子操作始终是完全原子的(即

acquire-release
)。排序参数仅与对“其他”数据的操作相关。因此,release仅意味着在操作之前发生的内存写入
其他位置
对于其他线程是可见的,类似地acquire意味着操作之后从
其他位置
读取内存将看到其他线程提交的所有内容操作时的线程。

© www.soinside.com 2019 - 2024. All rights reserved.