Rust问题:Arc内数据无法可变借用,但内部已用Mutex保护
Rust跨线程共享Db的实现问题与解决
问题背景
尝试实现一个需跨线程和函数共享的数据库Db示例,将Db结构体包裹在Arc中,并在结构体内部用Mutex保护成员:
pub struct Db{ pub db: Mutex<BTreeMap<String, String>>, }
但通过关联方法更新Db时出现错误:
help: trait
DerefMutis required to modify through a dereference, but it is not implemented forArc<Db>
未采用Arc::new(Mutex::new(Db))的方式,而是仅用Arc::new(Db),认为数据库内部成员已受Mutex保护,希望解决编译错误并确认这种方式是否推荐。
环境:rustc 1.65.0 (897e37553 2022-11-02)
错误原因
Arc<T>是共享所有权的线程安全智能指针,为保证线程安全,它并未实现DerefMut trait,因此无法通过Arc<Db>直接获取&mut Db类型的可变引用。如果关联方法定义为接收&mut self,编译器就会抛出上述错误——但实际上,内部的Mutex已经负责了可变访问的同步控制,根本不需要对整个Db实例进行可变引用。
解决方案
将关联方法的参数改为&self,通过self.db.lock()获取Mutex的锁后,再修改内部的BTreeMap。示例代码如下:
use std::sync::{Arc, Mutex}; use std::collections::BTreeMap; pub struct Db { pub db: Mutex<BTreeMap<String, String>>, } impl Db { // 插入数据:仅需&self,通过Mutex锁实现可变访问 pub fn insert(&self, key: String, value: String) -> Result<(), Box<dyn std::error::Error>> { // 获取Mutex锁,若当前有其他线程持有锁则阻塞等待 let mut map = self.db.lock()?; map.insert(key, value); Ok(()) } // 查询数据:同样通过锁访问只读数据 pub fn get(&self, key: &str) -> Option<String> { let map = self.db.lock().ok()?; map.get(key).cloned() } } fn main() -> Result<(), Box<dyn std::error::Error>> { let db = Arc::new(Db { db: Mutex::new(BTreeMap::new()), }); // 跨线程共享Db实例 let db_clone = Arc::clone(&db); std::thread::spawn(move || { db_clone.insert("name".to_string(), "Alice".to_string()).unwrap(); }).join()?; println!("name: {:?}", db.get("name")); Ok(()) }
方式合理性分析
这种Arc<Db>(Db内部含Mutex)的设计是推荐的,原因如下:
- 粒度更合理:可以针对结构体内部不同成员单独加锁,避免对整个结构体加锁导致的锁粒度太大,提升并发性能
- 结构更清晰:明确区分哪些成员需要线程同步保护,哪些是只读或无需同步的成员
- 扩展性更强:后续若要给Db添加其他成员,可灵活选择是否需要同步控制,无需修改外部的Arc包裹方式
内容的提问来源于stack exchange,提问作者O oLo O
相关产品推荐
相关产品推荐

