从互斥锁中同时借用引用和保护变量

5
我正在尝试封装一些代码,以避免重复,涉及从Mutex中借用数据并进行进一步操作(这些操作超出了本问题的范围,但是它们是推动因素)。
以下示例代码抱怨guard没有足够长的生命周期。但这正是我在专门设计用于此目的的结构中返回guard的原因。
这是借用检查器的限制吗?有什么关于解决此问题的建议吗?
use std::sync::{Mutex,MutexGuard};
use std::ops::DerefMut;

pub struct InnerData {
    count: i32  // sample only
}

pub struct Data {
    pub inner_data: Mutex<InnerData>
}

pub struct BorrowedInnerData<'a> {
    pub inner_data: &'a mut InnerData,
    guard: MutexGuard<'a,InnerData>,
}

impl Data {
    pub fn borrow_inner_data<'a>(&'a mut self) -> BorrowedInnerData<'a> {
        let guard = self.inner_data.lock().unwrap();
        BorrowedInnerData {
            inner_data: guard.deref_mut(),
            guard: guard,
        }
    }
}

fn main() {
    let mut data = Data {
        inner_data: Mutex::new( InnerData {
            count: 5
        }),
    };

    let borrowed_inner_data = data.borrow_inner_data();
}

考虑当结构体被移动时,内部指针会发生什么。 - Veedrac
1个回答

6

我们来看一下DerefMut trait

pub trait DerefMut: Deref {
    fn deref_mut(&'a mut self) -> &'a mut Self::Target;
}

这意味着当调用 deref_mut 时,将返回一个引用,该引用的生命周期与被解引用的值一样长。然而,当您将 guard 移动到 BorrowedInnerData 时,您正在移动它,这意味着该值停止在一个内存位置上并开始在新位置上。正如Veedrac所提示的那样,通过移动守卫,您可能会使引用失效。这将是非常糟糕的,并导致崩溃(在最好的情况下)。
然而,保留 guardinner_data 没有真正的理由。由于存在DerefDerefMutMutexGuard<InnerData>可以像&InnerData&mut InnerData一样使用。只需从结构中删除inner_data并保留guard

谢谢,这解决了疑惑。 :-) 不幸的是,在我的实际用例中,我仍然被大量重复的代码困扰。请参见http://pastebin.com/2Vy5RYmG以及run_thread()中的代码块,了解我的动机。我正在尝试在每次需要访问当前线程会话时减少重复。 - Ant Manelope
1
@AntManelope,我觉得我没有看出问题。在进行了一些重构之后,依据我的意见并没有太多的重复内容。 - Shepmaster
好的,我现在开始动手了。 - Ant Manelope

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接