独立于方法返回RWLockReadGuard [英] Returning a RWLockReadGuard independently from a method

查看:314
本文介绍了独立于方法返回RWLockReadGuard的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个对象类型

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对象.

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

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

但是,我一直无法做自己想做的事,遇到了各种各样的终生借贷问题等等.

是否有可能创建一种自成一类的句柄"对象,同时包含指向它指向的对象的锁和锁保护?

这与解决方案

中所述,为什么我不能存储值和中引用该值?,租用板条箱允许使用自引用结构在某些情况下.

#[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());
}

另请参阅:

I have an object of type

Arc<RwLock<SessionData>>

And I have a method that is supposed to take some kind of reference to SessionData

fn some_method(session: ...)

I'm using Rocket (a web-framework for Rust), and I can't directly invoke the method, because it is invoked by Rocket. However, I can provide it with an implementation that creates an object that will be passed to the handler. It looks a bit like this:

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
    }
}

I want to avoid returning an RwLock directly, because I want the handler to have an already-locked object passed to it. However, I can't return a reference or a RwLockReadGuard, because both of them depend on the RwLock, which would go out of scope.

Instead, I am trying to create some kind of self-sufficient type that would contain an Arc<RwLock<SessionData>>, contain the lock guard to this lock, and deref to a SessionData object.

So far, I have tried some combinations of the following:

  • A Session object that contains an Arc<RwLock<SessionData>> and a RwLockReadGuard<SessionData>
  • An object that contains an Arc<RwLock<SessionData>> and a RwLockReadGuardRef<SessionData> from the owning-ref library.
  • An object that would use the OwnedHandle type from the owning-ref library.

However, I haven't been able to do what I want to do, running into various lifetime borrowing issues and whatnot.

Is it at all possible to create a sort of a self-contained 'Handle'-like object that would contain both the lock and the lock guard to the object that it points to?

This is a similar, but slightly different situation than described in How to return reference to a sub-value of a value that is under a mutex?. In there, the MutexGuardRef internally depends on Mutex, and cannot exist if the Mutex (or MyStruct) goes out of scope. In order to achieve similar behaviour, I'd have to pass a struct that contains my RwLock and then do the locking inside the method. This is fine, but I'm wondering if I can go another step further, and pass a struct that is both independent and serves as a RwLockGuard, avoiding the need to lock manually.

Basically, I want to move the locking of the RwLock from the client to the provider of the value.

解决方案

As described in Why can't I store a value and a reference to that value in the same struct?, the Rental crate allows for self-referential structs in certain cases.

#[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());
}

See also:

这篇关于独立于方法返回RWLockReadGuard的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆