文档【免费下载链接】rfcsRFCs for changes to Rust项目地址https://gitcode.com/gh_mirrors/rf/rfcs点击查看免费下载导读本文围绕 Rust 官方 RFC 仓库rust-lang/rfcs中的 RFC 1649atomic_access 展开系统讲解该 RFC 为core::sync::atomic原子类型引入的两项核心能力get_mut/into_inner直接访问方法在独占访问下以非原子语义高效读取值以及原子类型与底层值类型布局始终一致的硬性保证为 FFI 场景如 Linux futex 系统调用奠定基础。读完本文你将理解为何普通 load/store 比load(Relaxed)更利于优化器、如何安全地在 Drop 实现与 FFI 中直接操作原子对象以及这一设计如何与仓库中的 RFC 1543integer_atomics、RFC 1758repr_transparent 相互呼应。一、RFC 概览一次补齐独占访问 API与布局契约的设计RFC 1649 于 2016 年 6 月提出提案内容可概括为两部分为所有原子类型新增两个方法签名统一为impl AtomicT { fn get_mut(mut self) - mut T; fn into_inner(self) - T; }其中AtomicT泛指AtomicBool、AtomicI8/16/32/64/128、AtomicU*、AtomicIsize、AtomicUsize、AtomicPtrT等标准原子类型这些具体类型的引入本身由 RFC 1543 定义见其文档开头的类型清单。指定原子类型的内存布局契约AtomicT的布局始终与底层类型T相同。例如AtomicI32被保证可与i32通过transmute互相转换the layout of anAtomicTtype is always the same as the underlyingTtype. So, for example,AtomicI32is guaranteed to be transmutable to and fromi32.这两点分别解决性能优化与FFI 互操作两类问题下文逐一展开。二、动机分析为什么需要 get_mut 与 into_inner1. 独占访问下绕过原子语义的合法性原子操作的存在意义是在多线程并发访问时保证同步与可见性。但当持有mut self或通过move消费原子对象时Rust 的所有权系统保证了不存在其他存活引用即没有任何其他线程可以同时访问该原子对象。此时再走一遍原子加载/存储的同步语义不仅是多余的还会带来可观的性能代价普通load/store即通过get_mut得到的mut T上的普通读写具有极弱的同步保证编译器可以对其进行充分的优化而load(Relaxed)/store(Relaxed)即便是最弱的原子语义也仍然是原子操作。RFC 明确指出LLVM 当前把所有原子操作包括 relaxed 级别都当作volatile 操作处理因此不执行任何优化——例如即使一次load(Relaxed)的结果在后续代码中完全未被使用编译器也不会将其消除。这一 volatile 背景并非孤例仓库中的 RFC 1467volatile 在动机部分同样提到稳定版此前只能通过滥用原子类型 load/store 的 volatile 语义rust-lang/rust#30962来实现稳定的 volatile 内存访问可见当时原子操作的 volatile 化处理是公认的已知事实。2. get_mut 的典型场景Drop 实现get_mut特别被期望用在Drop实现中此时你天然拥有mut self但往往需要读取其中某个原子字段的当前值。若改用self.flag.load(Ordering::Relaxed)由于上面提到的 volatile 语义编译器无法对这次加载做任何优化。示例如下基于 RFC 设计意图的演示代码struct Resource { active: AtomicBool, // ... 其他字段 } impl Drop for Resource { fn drop(mut self) { // drop 阶段持有 mut self不存在其他线程引用该原子对象 // 可以直接以普通引用方式读取编译器可自由优化。 if *self.active.get_mut() { // 执行清理逻辑 } } }3. into_inner不需要可变引用的提取into_inner与get_mut在功能上有所重叠但它的价值在于按值消费原子对象从而在对象本身不可变例如拥有的是非mut绑定时也能取出内部值。RFC 明确指出这两个方法是对Mutex::get_mut与Mutex::into_inner的镜像设计——Mutex早已提供同样的访问模式原子类型理应具备对等能力。let counter: AtomicUsize AtomicUsize::new(42); // 不需要 mutable 绑定直接按值取出内部值 let value: usize counter.into_inner(); assert_eq!(value, 42);4. 与 const 初始化上下文的配合原子类型在常量环境中的初始化是另一个重要的配套能力仓库中的 RFC 0911const-fn 就展示了通过const fn的new来初始化原子静态变量的方式例如static FLAG: AtomicBool AtomicBool::new(true);见该 RFC 的示例部分。get_mut/into_inner则补全了原子类型在运行时取用一侧的能力二者合起来构成了原子类型从初始化到独占读取的完整闭环。三、布局保证FFI 与跨进程共享场景的基石1. 保证内容RFC 明确将布局保证表述为一条文档化契约AtomicT与T的布局始终一致。这意味着AtomicI32可与i32双向transmuteAtomicBool可与bool双向transmuteRFC 1543 为此特意将AtomicBool内部改为基于AtomicU8实现使其能安全地 transmute 为bool与其他布局与底层类型一致的原子类型保持一致。这一保证主要面向FFI当一段内存需要被以原子方式修改、但声明的类型本身是非原子类型时布局一致性是安全操作的前提。2. 最典型的用例Linux futex 系统调用RFC 给出的最典型例子是Linux futex 系统调用。futex 接收一个int*参数指向一个由用户态与内核同时原子修改的整数The most common example of this is the Linuxfutexsystem call which takes anint*parameter pointing to an integer that is atomically modified by both userspace and the kernel.在此之前Rust 代码调用 futex 时往往直接把原子对象的地址传给系统调用——这实际是在假设原子类型与底层整数类型布局相同但当时文档并未给出此保证。RFC 1649 的布局保证让这一假设变得名正言顺。示例基于 RFC 设计意图的演示use core::sync::atomic::{AtomicI32, Ordering}; // 布局保证后AtomicI32 与 i32 布局一致 // 因此可以把 AtomicI32 作为 int* 传给 futex。 let futex_word AtomicI32::new(0); let addr futex_word as *const AtomicI32 as *const i32; // 将 addr 传给 futex(addr, FUTEX_WAIT, ...) / futex(addr, FUTEX_WAKE, ...)值得注意的是此场景与 RFC 1543integer_atomics 的动机紧密衔接futex 基于原子i32变量而 x86_64 上原有的AtomicIsize是 64 位因此需要新增AtomicI32等定长原子类型RFC 1543 文档同样明确写道futex 代码会假设AtomicI32可以直接作为i32传给系统调用。两个 RFC 合在一起才让Rust 原子类型 futex的完整链路成立。3. 反向操作原子修改非原子声明的值布局保证还允许反向操作——通过指针转换让 Rust 代码原子地修改一个并未声明为原子类型的值FFI 结构体结构体由 C 库创建的线程共享Rust 侧需要对其字段做原子修改内存映射文件映射文件中某字段被另一个进程共享需要原子地修改。示例基于 RFC 设计意图的演示// 假设一个 C 侧声明的结构体字段非原子类型需要被原子修改 let p mut shared_struct.counter as *mut i32 as *mut AtomicI32; p.write(1, Ordering::Release);4. 与 repr(transparent) 的呼应仓库中的 RFC 1758repr_transparent 在设计部分明确引用 RFC 1649 作为动机之一#[repr(transparent)]类型使得包装结构体与其唯一字段具有相同表示而 RFC 1649 要求AtomicUsize之类的类型与其底层类型表示一致——两者共同服务于类型包装不改变底层 ABI 表示这一 FFI 核心需求。四、实现细节基于 UnsafeCell::get 的平凡实现RFC 在 Detailed design 部分指出这些函数的实现基本是平凡的因为它们基于UnsafeCell::getThe actual implementations of these functions are mostly trivial since they are based onUnsafeCell::get.原理上标准原子类型内部本质上是UnsafeCellT的包装RFC 0911 的示例代码中就以struct AtomicUsize { v: UnsafeCellusize }展示了这一内部形态。UnsafeCell::get返回内部值的裸指针配合mut self/self的所有权上下文即可安全地构造出mut T或按值取出T。更重要的是RFC 明确声明The existing implementations of atomic types already have the same layout as the underlying types (evenAtomicBoolandbool), so no change is needed here apart from the documentation.也就是说布局保证在实现层面早已成立本 RFC 的实质工作是把它从事实升级为文档契约使其可被稳定 API 用户依赖。这与 RFC 1543 对AtomicBool的内部结构调整改用AtomicU8从而能安全 transmute 为bool相互配合共同巩固布局与底层类型一致这一族约束。此外into_inner的命名也符合仓库中 RFC 0430finalizing-naming-conventions 所确立的into_系列命名惯例unwrap、into_foo与into_inner的约定在标准库中一脉相承。五、权衡与备选方案1. 缺点DrawbacksRFC 坦诚地列出了两个缺点功能重叠into_inner与get_mut功能上有一定重叠存在 API 冗余之嫌失去布局调整空间一旦把布局与底层类型一致固化为契约标准库就失去了未来改变原子类型布局的能力。但 RFC 认为这并无大碍——原子类型直接映射到硬件原语硬件的原子指令天然以对应宽度工作不存在需要调整布局的现实动机。2. 备选方案Alternativesget_mut与into_inner的功能理论上可以用load(Relaxed)实现但 RFC 明确指出后者会产生更差的代码因为 relaxed 原子加载在优化器LLVM中处理得很差——如前文所述LLVM 将一切原子操作视为 volatile拒绝对其进行消除、合并等优化。这正是本设计宁愿新增专门 API而非复用现有原子 API的根本原因。六、遗留问题与如何在仓库中追踪RFC 结尾的 Unresolved questions 为None即设计在提出时已无悬而未决的问题其实现追踪 issue 为 rust-lang/rust#35603。若想在当前仓库中完整追踪这条设计脉络推荐按以下路径阅读关注点仓库路径关键内容本 RFC 全文text/1649-atomic-access.md方法签名、布局保证、动机与权衡原子类型体系text/1543-integer_atomics.mdAtomicI8~AtomicU128、target_has_atomic、AtomicBool内部改为AtomicU8布局一致性配套text/1758-repr-transparent.md#[repr(transparent)]显式引用 RFC 1649常量初始化配套text/0911-const-fn.mdAtomicBool::new(true)等 const 初始化示例volatile 语义背景text/1467-volatile.mdLLVM volatile 语义与原子操作的关联RFC 撰写模板0000-template.md本仓库 RFC 文档的统一结构Summary/Motivation/Detailed design 等仓库与流程说明README.mdRust RFC 流程、目录结构与贡献约定若希望本地精读可执行git clone https://gitcode.com/gh_mirrors/rf/rfcs后直接查阅上述文件。结语RFC 1649 是一份小而关键的标准库设计提案它以两个简洁的方法get_mut、into_inner补全了原子类型在独占访问场景下的高效读取路径并以一条布局契约AtomicT与T布局始终一致把 FFI 场景中长期默认成立但未文档化的假设变成正式承诺。与 RFC 1543、RFC 1758 一道它构成了 Rust 原子类型在性能、FFI 与 ABI 一致性三方面共同演进的完整图景。理解这份 RFC也就理解了为什么现代 Rust 中把AtomicI32当作i32传给 C 系统调用是安全且被文档保证的。赞分享文档【免费下载链接】rfcsRFCs for changes to Rust项目地址https://gitcode.com/gh_mirrors/rf/rfcs点击查看免费下载相关推荐Rust 整型原子类型扩展RFC 1543深度解读从 AtomicI8 到 AtomicU128 与 target_has_atomicRust 整型原子类型扩展RFC 1543深度解读从 AtomicI8 到 AtomicU128 与 target_has_atomic 导读 本文以仓库文档Rust RFC 1444 深度解读union 原生语法设计——从 FFI 绑定到内存高效类型Rust RFC 1444 深度解读union 原生语法设计——从 FFI 绑定到内存高效类型 导读 本文基于 Rust RFC 仓库中的 text/1444文档Rust 原子库中的 volatile 存储语义store_volatile 与 I/O 内存访问深度解析Rust 原子库中的 volatile 存储语义 store_volatile 与 I/O 内存访问深度解析 导读 本文围绕 Rust 标准库 core 中新编程语言编译器语言运行时标准库上一篇探索未来编程新可能Ollama Python下一篇从DSD到FLAC为什么数十万用户选择放弃古董音频格式创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考