You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust中Arc的drop实现里Acquire-Release内存序的工作原理

关于简化版Arc实现中Drop逻辑的内存序疑问解答

首先明确核心前提:fetch_sub是原子操作,它的“读取当前值→减1→写入新值”是一个不可分割的整体,多个线程对同一个原子变量的原子操作会被串行化执行,不会出现中间步骤被打断的情况。

疑问1:是否会出现两个线程都读到2、写入1,导致值永远不被drop?

这种情况不可能发生。

原子操作的串行化特性决定了,线程A和线程B的fetch_sub必然是先后完整执行的:

  • 假设初始strong值为2,线程A先执行fetch_sub(1, Release):它会读取到2,写入1,返回值为2,不会进入drop分支。
  • 接着线程B执行fetch_sub(1, Release):此时它读取到的是1,写入0,返回值为1,触发后续的drop逻辑。

反过来,若线程B先执行,结果也是一样——总有一个线程会读取到1,进而触发drop,不会出现计数停留在1的情况。

疑问2:仅在读取到1时执行Acquire fence,如何保证同步、无数据竞争且能读到1?

无数据竞争的保证

所有对strong的操作(fetch_add用于clone,fetch_sub用于drop)都是原子操作,Rust的内存模型保证原子操作之间不存在数据竞争,每个操作都能正确读取到原子变量的当前值。

必然能读取到1的原因

strong的初始值对应Arc的持有数量:创建Arc时初始为1,每clone一次就fetch_add(1)增加计数,每drop一次就fetch_sub(1)减少计数。最终计数必然会从1减到0,此时执行fetch_sub的线程会读取到1(返回值为1),从而进入drop分支,不存在永远读不到1的可能。

同步关系的建立

  • 当线程执行fetch_sub(Release)时,Release语义保证:该线程中所有在fetch_sub之前对Arc内部数据的修改,都会被后续执行Acquire操作的线程看到。
  • 当某个线程读取到返回值1(即它是最后一个持有Arc的线程),执行fence(Acquire)会与所有之前执行fetch_sub(Release)的线程建立synchronize-with关系,进而保证:其他线程对Arc内部数据的所有修改,都happens-before当前线程的drop操作,确保drop时能看到完整的、正确的内部状态。

这种“Release fetch_sub + 条件性Acquire fence”是一种性能优化:只有最后一个线程需要承担Acquire屏障的开销,其他线程只需执行轻量的Release语义操作,避免了不必要的内存屏障开销。


内容的提问来源于stack exchange,提问作者Samuel Yvon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 12:40:19