使用隐式锁定取消引用 Mutex/RwLock 到内部对象
Deref Mutex/RwLock to inner object with implicit locking
我有一个结构 Obj
,它有一个很大的 API,我也想通过 Arc<RwLock<Obj>>
使用它。我已经定义了一个 struct ObjRef(Arc<RwLock<Obj>>)
并且想在 ObjRef
上调用 Obj
的函数,而不需要每次都调用 .read().unwrap()
或 .write().unwrap()
。 (ObjRef
实现了 Deref<Target=Arc<RwLock<Obj>>
,所以我只需要调用 objRef.read().unwrap()
)
我可以像这样为 ObjRef
再次实现 Obj
的所有功能:
impl ObjRef {
fn foo(&self, arg: Arg) -> Ret {
self.read().unwrap().foo(arg)
}
}
但是对每个函数都这样做会导致大量样板文件。
为 ObjRef
实现 Deref<Target=Obj>
不起作用,因为 deref
实现将返回对 .read().unwrap()
返回的 RwReadLockGuard
对象的引用将在 deref
:
之后删除
impl Deref for ObjRef {
type Target = Obj;
fn deref(&self) -> &Self::Target {
let guard: RwLockReadGuard<'_, Obj> = self.0.read().unwrap();
&*guard // <- return reference to Obj referenced by guard
// guard is dropped now, reference lifetime ends
}
}
有没有办法通过在内部进行锁定的低样板实现来调用 Obj
Api?
我正在考虑为 Api 引入一个特征,其中包含 Api 的默认实现和一个由特征用户实现的单一函数以获得通用 Deref<Target=Obj>
,但这会使 Api 受到一些限制,例如使用通用参数将变得更加复杂。
是否有更好的方法,可以让我通过锁使用任何 Obj
而无需每次都显式调用锁定机制?
不可能通过 Deref
做到这一点,因为 Deref::deref
总是 returns 一个简单的引用——它的有效性必须仅取决于继续存在的论点(它借用检查员理解),而不是任何其他状态,例如“锁定”。
此外,将锁定一般地添加到没有它的设计的接口是危险的,因为它可能会意外导致死锁,或者由于按顺序执行两个本应使用 单个操作完成的操作而导致意外结果 锁定。
我建议考虑将您的类型内部设为Arc<RwLock
,即
pub struct Obj {
lock: Arc<RwLock<ObjData>>,
}
// internal helper, not public
struct ObjData {
// whatever fields Obj would have had go here
}
然后,您可以直接在 Obj
上定义您的方法一次,调用者永远不需要显式处理锁,但您的方法可以根据需要准确地处理它。这是从中受益的问题域中相当常见的模式,例如 UI 个对象。
如果有某种原因 Obj
确实需要在有锁或没有锁的情况下使用,那么定义一个特征。
我有一个结构 Obj
,它有一个很大的 API,我也想通过 Arc<RwLock<Obj>>
使用它。我已经定义了一个 struct ObjRef(Arc<RwLock<Obj>>)
并且想在 ObjRef
上调用 Obj
的函数,而不需要每次都调用 .read().unwrap()
或 .write().unwrap()
。 (ObjRef
实现了 Deref<Target=Arc<RwLock<Obj>>
,所以我只需要调用 objRef.read().unwrap()
)
我可以像这样为 ObjRef
再次实现 Obj
的所有功能:
impl ObjRef {
fn foo(&self, arg: Arg) -> Ret {
self.read().unwrap().foo(arg)
}
}
但是对每个函数都这样做会导致大量样板文件。
为 ObjRef
实现 Deref<Target=Obj>
不起作用,因为 deref
实现将返回对 .read().unwrap()
返回的 RwReadLockGuard
对象的引用将在 deref
:
impl Deref for ObjRef {
type Target = Obj;
fn deref(&self) -> &Self::Target {
let guard: RwLockReadGuard<'_, Obj> = self.0.read().unwrap();
&*guard // <- return reference to Obj referenced by guard
// guard is dropped now, reference lifetime ends
}
}
有没有办法通过在内部进行锁定的低样板实现来调用 Obj
Api?
我正在考虑为 Api 引入一个特征,其中包含 Api 的默认实现和一个由特征用户实现的单一函数以获得通用 Deref<Target=Obj>
,但这会使 Api 受到一些限制,例如使用通用参数将变得更加复杂。
是否有更好的方法,可以让我通过锁使用任何 Obj
而无需每次都显式调用锁定机制?
不可能通过 Deref
做到这一点,因为 Deref::deref
总是 returns 一个简单的引用——它的有效性必须仅取决于继续存在的论点(它借用检查员理解),而不是任何其他状态,例如“锁定”。
此外,将锁定一般地添加到没有它的设计的接口是危险的,因为它可能会意外导致死锁,或者由于按顺序执行两个本应使用 单个操作完成的操作而导致意外结果 锁定。
我建议考虑将您的类型内部设为Arc<RwLock
,即
pub struct Obj {
lock: Arc<RwLock<ObjData>>,
}
// internal helper, not public
struct ObjData {
// whatever fields Obj would have had go here
}
然后,您可以直接在 Obj
上定义您的方法一次,调用者永远不需要显式处理锁,但您的方法可以根据需要准确地处理它。这是从中受益的问题域中相当常见的模式,例如 UI 个对象。
如果有某种原因 Obj
确实需要在有锁或没有锁的情况下使用,那么定义一个特征。