使用隐式锁定取消引用 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 确实需要在有锁或没有锁的情况下使用,那么定义一个特征。