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

为何以下Mutex无法被多线程共享?Rust编译错误排查

Rust线程安全错误分析与解决

Rust代码实现

pub fn with_lock<T>(f: &dyn Fn(&mut Connection) -> T) -> T {
    let mut guard = Connection::mutex().lock().unwrap();
    let re = f(&mut *guard);
    re
}

pub fn start() -> Result<()> {
    let fusion = Arc::new(any_fusion()?);
    let fusion_clone = Arc::clone(&fusion);
    let fusion_m = Mutex::new(fusion_clone);

    let handle = thread::spawn(|| {
        // Task to be executed in the new thread
        loop {
            fusion_m.lock().unwrap().update();
        }
    });

    Self::with_lock(&|c| {
        c.fusion = Some(*fusion);
        c.thread = Some(handle);
    });

    Ok(())
}

编译错误信息

error[E0277]: `dyn Fusion` cannot be shared between threads safely
   --> src/lib.rs:189:36
    |
189 |           let handle = thread::spawn(|| {
    |  ______________________-------------_^
    | |                      |
    | |                      required by a bound introduced by this call
190 | |             // Task to be executed in the new thread
191 | |             loop {
192 | |                 fusion_m.lock().unwrap().update();
193 | |             }
194 | |         });
    | |_________^ `dyn Fusion` cannot be shared between threads safely
    |
    = help: the trait `Sync` is not implemented for `dyn Fusion`
    = note: required for `Unique<dyn Fusion>` to implement `Sync`

问题原因

你觉得Mutex<Arc<dyn Fusion>>应该线程安全,但忽略了Rust对trait对象的线程安全约束:

  1. Arc<T>要实现Send和Sync,要求内部的T必须同时满足Send trait和Sync trait——因为Arc是线程安全的引用计数容器,允许跨线程共享和转移所有权。
  2. 这里的T是dyn Fusion,默认情况下trait对象不会自动继承Send和Sync,除非Fusion trait本身标注了这些超级约束,或者创建trait对象时明确附加这些约束。
  3. 错误提示里的Unique<dyn Fusion>是Arc内部管理内存的类型,它需要dyn Fusion实现Sync才能满足线程安全,而当前dyn Fusion没有这个实现,导致Arc<dyn Fusion>不满足线程安全要求,进而Mutex<Arc<dyn Fusion>>无法被安全地move到新线程的闭包中(thread::spawn要求闭包实现Send)。

解决方案

有两种可行的修复方式:

方式一:给Fusion trait添加Send + Sync超级约束

在定义Fusion trait时,直接把Send和Sync作为超级trait,这样所有实现该trait的类型都会自动继承线程安全约束:

trait Fusion: Send + Sync {
    fn update(&self);
    // 其他方法定义...
}

方式二:创建trait对象时明确指定Send + Sync约束

如果无法修改Fusion trait的定义,可以在创建Arc时,给trait对象附加Send + Sync约束:

// 修改start函数中的fusion创建语句
let fusion = Arc::new(any_fusion()? as dyn Fusion + Send + Sync);
let fusion_clone = Arc::clone(&fusion);

这样Arc<dyn Fusion + Send + Sync>会自动实现Send和Sync,Mutex包裹它之后就能满足线程安全要求,闭包也能被thread::spawn正常接受。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 04:17:02