独立于方法返回 RWLockReadGuard
Returning a RWLockReadGuard independently from a method
我有一个类型的对象
Arc<RwLock<SessionData>>
我有一个方法应该参考 SessionData
fn some_method(session: ...)
我正在使用 Rocket(Rust 的网络框架),我无法直接调用该方法,因为它是由 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
}
}
我想避免直接 returning 一个 RwLock
,因为我希望处理程序将一个已锁定的对象传递给它。但是,我不能 return 引用或 RwLockReadGuard
,因为它们都依赖于 RwLock
,这会超出范围。
相反,我正在尝试创建某种自给自足的类型,它包含一个 Arc<RwLock<SessionData>>
,包含此锁的锁守卫,并取消对 SessionData
对象的引用。
到目前为止,我已经尝试了以下的一些组合:
- 包含一个
Arc<RwLock<SessionData>>
和一个 RwLockReadGuard<SessionData>
的 Session
对象
- 包含来自 owning-ref 库的
Arc<RwLock<SessionData>>
和 RwLockReadGuardRef<SessionData>
的对象。
- 将使用 owning-ref 库中的
OwnedHandle
类型的对象。
然而,我一直没能做我想做的事,运行陷入各种终身借贷问题等等。
是否有可能创建一种类似于 自包含 'Handle' 的对象,同时包含它指向的对象的锁和锁守卫?
这与 中描述的情况类似,但略有不同。在那里,MutexGuardRef
内部依赖于 Mutex
,并且如果 Mutex
(或 MyStruct
)超出范围则不存在。为了实现类似的行为,我必须传递一个包含我的 RwLock
的结构,然后在方法内部进行锁定。这很好,但我想知道我是否可以更进一步,传递一个既 independent 又作为 RwLockGuard
[ 的结构=66=],避免手动锁定的需要。
基本上,我想将 RwLock
的锁定从客户端移动到值的提供者。
如 , the 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());
}
另请参阅:
- Returning the T borrowed from RefCell<T>
如果有人需要其他解决方案,那么这里是使用 ouroboros 重写的 @Shelpmaster 示例:
use ouroboros::self_referencing;
use std::sync::{Arc, RwLock, RwLockReadGuard};
struct SessionData;
impl SessionData {
fn hello(&self) -> u8 {
42
}
}
#[self_referencing]
pub struct OwningReadGuard<T>
where
T: 'static,
{
lock: Arc<RwLock<T>>,
#[covariant]
#[borrows(lock)]
guard: RwLockReadGuard<'this, T>,
}
fn owning_lock(lock: Arc<RwLock<SessionData>>) -> OwningReadGuard<SessionData> {
OwningReadGuardBuilder {
lock,
guard_builder: |l: &Arc<RwLock<SessionData>>| l.read().unwrap(),
}
.build()
}
fn main() {
let session = Arc::new(RwLock::new(SessionData));
let lock = owning_lock(session.clone());
println!("{}", lock.borrow_guard().hello());
assert!(session.try_read().is_ok());
assert!(session.try_write().is_err());
drop(lock);
assert!(session.try_write().is_ok());
}
我有一个类型的对象
Arc<RwLock<SessionData>>
我有一个方法应该参考 SessionData
fn some_method(session: ...)
我正在使用 Rocket(Rust 的网络框架),我无法直接调用该方法,因为它是由 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
}
}
我想避免直接 returning 一个 RwLock
,因为我希望处理程序将一个已锁定的对象传递给它。但是,我不能 return 引用或 RwLockReadGuard
,因为它们都依赖于 RwLock
,这会超出范围。
相反,我正在尝试创建某种自给自足的类型,它包含一个 Arc<RwLock<SessionData>>
,包含此锁的锁守卫,并取消对 SessionData
对象的引用。
到目前为止,我已经尝试了以下的一些组合:
- 包含一个
Arc<RwLock<SessionData>>
和一个RwLockReadGuard<SessionData>
的 - 包含来自 owning-ref 库的
Arc<RwLock<SessionData>>
和RwLockReadGuardRef<SessionData>
的对象。 - 将使用 owning-ref 库中的
OwnedHandle
类型的对象。
Session
对象
然而,我一直没能做我想做的事,运行陷入各种终身借贷问题等等。
是否有可能创建一种类似于 自包含 'Handle' 的对象,同时包含它指向的对象的锁和锁守卫?
这与 MutexGuardRef
内部依赖于 Mutex
,并且如果 Mutex
(或 MyStruct
)超出范围则不存在。为了实现类似的行为,我必须传递一个包含我的 RwLock
的结构,然后在方法内部进行锁定。这很好,但我想知道我是否可以更进一步,传递一个既 independent 又作为 RwLockGuard
[ 的结构=66=],避免手动锁定的需要。
基本上,我想将 RwLock
的锁定从客户端移动到值的提供者。
如
#[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());
}
另请参阅:
- Returning the T borrowed from RefCell<T>
如果有人需要其他解决方案,那么这里是使用 ouroboros 重写的 @Shelpmaster 示例:
use ouroboros::self_referencing;
use std::sync::{Arc, RwLock, RwLockReadGuard};
struct SessionData;
impl SessionData {
fn hello(&self) -> u8 {
42
}
}
#[self_referencing]
pub struct OwningReadGuard<T>
where
T: 'static,
{
lock: Arc<RwLock<T>>,
#[covariant]
#[borrows(lock)]
guard: RwLockReadGuard<'this, T>,
}
fn owning_lock(lock: Arc<RwLock<SessionData>>) -> OwningReadGuard<SessionData> {
OwningReadGuardBuilder {
lock,
guard_builder: |l: &Arc<RwLock<SessionData>>| l.read().unwrap(),
}
.build()
}
fn main() {
let session = Arc::new(RwLock::new(SessionData));
let lock = owning_lock(session.clone());
println!("{}", lock.borrow_guard().hello());
assert!(session.try_read().is_ok());
assert!(session.try_write().is_err());
drop(lock);
assert!(session.try_write().is_ok());
}