0

我正在尝试使用静态 HashMap<String, Object> 来存储一些我想在未来全局使用和修改的数据。我发现声明这种全局映射的某种方式是使用lazy_static 和互斥锁,以便安全地共享数据。但是,当我想将这些对象作为参考返回时,我遇到了一些所有权问题,就像我在上面的代码中所做的那样:

use std::error::Error;
use std::collections::HashMap;
use std::sync::Mutex;
use super::domain::{Session, SessionRepository}; // object and trait declaration

lazy_static! {
    static ref REPOSITORY: Mutex<HashMap<String, Session>> = {
        let mut repo = HashMap::new();
        Mutex::new(repo)
    };    
}

impl SessionRepository for REPOSITORY {
    fn find(cookie: &str) -> Result<&mut Session, Box<dyn Error>> {
        let mut repo = REPOSITORY.lock()?;
        if let Some(sess) = repo.get_mut(cookie) {
            return Ok(sess);
        }

        Err("Not found".into())
    }
}

所以问题是:有没有办法正确地做到这一点?Rust 中是否存在我可以用来实现这种行为的任何设计模式?

非常感谢!

4

1 回答 1

5

您尝试做的事情被编译器正确拒绝,因为如果您可以返回引用,那么可能会发生不好的事情。由于函数返回后,互斥体不再锁定,

  1. 其他一些线程可以锁定互斥体并获得它自己的对会话的可变引用,这违反了可变引用提供独占访问的规则。
  2. 其他一些线程可以锁定互斥体并从 HashMap中删除会话——现在您正在访问已释放的内存。

解决方案:每个会话都应该在自己的 Arc<Mutex<_>>. 那是:

lazy_static! {
    static ref REPOSITORY: Mutex<HashMap<String, Arc<Mutex<Session>>>> = {
        ...

impl SessionRepository for REPOSITORY {
    fn find(cookie: &str) -> Result<Arc<Mutex<Session>>, Box<dyn Error>> {
        let mut repo = REPOSITORY.lock()?;
        if let Some(sess) = repo.get(cookie) {
            return Ok(Arc::clone(sess));
        }
        ...
    }

允许会话通过Arc存储库和调用它的任何线程保持活动find()状态,从而获得它们自己的Arc引用计数指针的克隆。Mutex允许每个会话独立变异。

于 2021-07-10T00:31:31.390 回答