独立于方法返回RWLockReadGuard

时间:2018-05-23 20:23:16

标签: rust borrow-checker rwlock

我有一个

类型的对象
Arc<RwLock<SessionData>>

我有一个方法应该对SessionData

进行某种引用
fn some_method(session: ...)

我正在使用Rocket(Rust的Web框架),我不能直接调用该方法,因为它是由Rocket调用的。但是,我可以为它提供一个实现,该实现创建一个将传递给处理程序的对象。看起来有点像这样:

impl<'a, 'r> request::FromRequest<'a, 'r> for SomeType {
    type Error = ();

    fn from_request(request: &'a request::Request<'r>) -> request::Outcome<Self, Self::Error> {
        // return object here
    }
}

我想避免直接返回RwLock,因为我希望处理程序将一个已锁定的对象传递给它。但是,我无法返回引用或RwLockReadGuard,因为它们都依赖于RwLock,这将超出范围。

相反,我正在尝试创建一种包含Arc<RwLock<SessionData>>的自足类型,包含此锁的锁定保护,并解析为SessionData对象。

到目前为止,我已经尝试了以下几种组合:

  • 包含SessionArc<RwLock<SessionData>>
  • RwLockReadGuard<SessionData>对象
  • 包含owning-ref库中的Arc<RwLock<SessionData>>RwLockReadGuardRef<SessionData>的对象。
  • 将使用owning-ref库中的OwnedHandle类型的对象。

然而,我无法做我想做的事情,遇到各种终身借贷问题等等。

是否可以创建一种自包含的“Handle”类对象,它包含锁定和锁定到它所指向的对象的锁定?

这与How to return reference to a sub-value of a value that is under a mutex?中描述的情况类似但略有不同。在那里,MutexGuardRef内部取决于Mutex,如果Mutex(或MyStruct)超出范围,则不能存在。为了实现类似的行为,我必须传递一个包含我的RwLock的结构,然后在方法内部进行锁定。这很好,但我想知道我是否可以再向前迈一步,并传递一个既强独立的结构,又作为 RwLockGuard ,避免需要手动锁定。

基本上,我想将RwLock从客户端锁定到值的提供者。

1 个答案:

答案 0 :(得分:5)

Why can't I store a value and a reference to that value in the same struct?所述,Rental crate在某些情况下允许自引用结构。

#[macro_use]
extern crate rental;

use std::sync::{Arc, RwLock};

struct SessionData;
impl SessionData {
    fn hello(&self) -> u8 { 42 }
}

rental! {
    mod owning_lock {
        use std::sync::{Arc, RwLock, RwLockReadGuard};

        #[rental(deref_suffix)]
        pub struct OwningReadGuard<T>
        where
            T: 'static,
        {
            lock: Arc<RwLock<T>>,
            guard: RwLockReadGuard<'lock, T>,
        }
    }
}

use owning_lock::OwningReadGuard;

fn owning_lock(session: Arc<RwLock<SessionData>>) -> OwningReadGuard<SessionData> {
    OwningReadGuard::new(session, |s| s.read().unwrap())
}

fn main() {
    let session = Arc::new(RwLock::new(SessionData));

    let lock = owning_lock(session.clone());
    println!("{}", lock.hello());

    assert!(session.try_read().is_ok());
    assert!(session.try_write().is_err());

    drop(lock);

    assert!(session.try_write().is_ok());
}

另见: