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

Rust多线程开发中能否无锁使用Arc并修改其内部值?

问题结论

你写的这段无锁直接修改Arc内部值的代码完全不合法,连编译阶段都无法通过,不存在可运行性。


核心原因说明
  • Arc<T>的作用仅为实现原子引用计数的跨线程共享所有权,它只保证引用计数的增减操作是线程安全的,不负责内部数据的并发可变访问安全。Arc<T>默认对外暴露的是内部值的不可变共享引用&T,你直接写*x += 1尝试修改内部值,首先就违反了Rust的基本借用规则,编译器会直接抛出cannot assign to data in an Arc``的错误。
  • 「不关心读取顺序」不能作为绕过并发安全规则的理由:Rust的安全抽象会在编译期彻底禁止数据竞争(Data Race),数据竞争属于未定义行为,哪怕你业务逻辑上能接受读到旧值/新值的任意结果,编译器也不会允许安全代码中出现这类风险。不要尝试用unsafe块绕过编译检查直接修改普通Arc包裹的内部值,这类写法会触发数据竞争,可能出现值错乱、程序崩溃等完全不可预期的运行问题。
  • Arc本身从来不是用来替代锁或者原子类型的:如果你确实需要跨线程共享可变数据,要根据场景选择搭配的类型:
    • 简单数值、布尔值这类基础类型的无锁并发场景,直接用Arc<AtomicI32>/Arc<AtomicBool>等标准库原子类型即可,这类类型本身实现了无锁的线程安全读写,不需要额外加互斥锁
    • 复杂自定义类型的并发可变场景,使用Arc<Mutex<T>>/Arc<RwLock<T>>搭配锁实现安全访问,不要尝试直接修改Arc包裹的普通值。

修正示例

如果你要实现代码里跨线程计数、子线程读值的逻辑,符合你「不关心读写顺序」需求的无锁写法可以参考如下实现:

use std::{
    sync::{
        atomic::{AtomicI32, Ordering},
        Arc,
    },
    thread,
};

fn main() {
    // 用Arc包裹原子类型实现无锁共享可变访问
    let x = Arc::new(AtomicI32::new(0));
    let y = Arc::clone(&x);
    thread::spawn(move || {
        for i in 0..10 {
            // 用Relaxed内存序不强制读写顺序,符合你的需求,性能开销极低
            let val = y.load(Ordering::Relaxed);
            println!("exe:{},{}", i, val);
        }
    });

    loop {
        let cur = x.load(Ordering::Relaxed);
        if cur >= 100000 {
            break;
        }
        // 写操作同样为原子操作,无锁
        x.store(cur + 1, Ordering::Relaxed);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 18:48:19