我正在编写一些 tokio 异步代码。我有一个多索引数据结构,将用户保留在我想要使用粗粒度锁(与每个对象锁相反)保护他们的位置。我有这样的事情:
use tokio::sync::RwLock;
struct User {
id: u64,
name: String,
}
// This class is not thread-safe.
struct UserDb {
by_id: HashMap<u64, Arc<RefCell<User>>>,
by_name: HashMap<String, Arc<RefCell<User>>>,
}
impl UserDb {
pub fn add_user(&mut self, name: String) -> Result<(), Error> {
// ...
}
}
// This class is thread-safe.
struct AsyncDb {
users: RwLock<UserDb>,
}
impl AsyncDb {
pub async fn add_user(&self, name: String) -> Result<(), Error> {
self.users.write().await.add_user(name)
}
}
// QUESTION: Are these safe?
unsafe impl Send for AsyncDb {}
unsafe impl Sync for AsyncDb {}
如果末尾没有Send
and特征,编译器会抱怨不是and (合理地如此),因此通过 . 访问/修改是不安全的。Sync
RefCell<User>
Send
Sync
AsyncDb::add_user
我的解决方案是实现Send
和数据结构,因为周围Sync
有一个粗粒度锁,其中包含所述s。AsyncDb
UserDb
RefCell
这是正确的解决方案吗?它是否违反了任何不变量?有更好的方法来处理这个问题吗?
注意:这里是 Rust 初学者。我可能有很多概念上的差距,所以如果事情没有意义,请指出。