从RwLock访问T<Vec<RwLock<T>>>

问题描述 投票:0回答:1

我有一个应该在多个线程中传递的结构。其结构如下:

pub struct State{
    humans: RwLock<Vec<RwLock<Human>>,
    animals: RwLock<Vec<RwLock<Animal>>
}

这个想法是,如果线程只写入单个 Vec 元素,则不会锁定整个 Vec,而是只能读取相应的元素和所有其他元素。另一方面,当从 Vec 插入/删除时,它肯定会被完全锁定。

现在我还有一个函数,它返回一个特定的

Human
。为简单起见,它始终返回
N^2
元素。

impl State{
    pub fn get_some_element(&self, N: usize) -> &Human{
        // here i am a bit lost, because I run into temporary variables that cannot be passed, when unwrapping the LockGuards. 
    }
}

我的一个想法是使用

tokio::sync::RwLockReadGuard::map

let humans = self.humans.read().await;
RwLockReadGuard::map(humans, |f|{
    &f.get(N^2)
}

由于临时变量的存在,甚至无法返回(因此 LockGuard 到相应的元素)。

您能在这里帮助我并就如何有效解决该问题提供一些建议吗?谢谢你。

asynchronous rust concurrency rust-tokio
1个回答
0
投票

您无法从锁中获得简单的参考。即使在嵌套锁情况之外,这也不起作用:

fn read_lock(lock: &std::sync::RwLock<i32>) -> &i32 {
    lock.read().unwrap()
}

原因是

read().unwrap()
给你一个
RwLockReadGuard
。它看起来有点像共享引用,但事实并非如此。特别是,它是一个具有自己的析构函数的结构,该析构函数在执行时会释放锁。您无法通过 Rust 中的简单引用获得这种过期后行为。

另外,只是为了强调这一点:嵌套锁在这里没有什么区别。仍然必须执行“一些”代码来负责释放“每个”锁。只要看一下签名,我们就应该在返回类型中看到 RwLockReadGuard<RwLockReadGuard<Human>> 形式的内容。不幸的是,这似乎无法直接实现。 stdlib RwLock 没有任何

map
函数,并且
tokio
仅当您可以将内部内容作为简单引用获取时才有用,而不是作为受锁保护保护的另一件事(并且
async
也有点碍事)。
因此,在这一点上,我建议要么将返回类型更改为泄漏更多数据结构的类型(例如返回锁而不是对内容的引用),如评论中所建议的;或者更改接口以使用闭包来处理获取的引用(类似于 
with
上的

RefCell

方法及类似方法):

fn with_element<F: FnOnce<&Human>>(&self, n: usize, f: F) { ... }
    

© www.soinside.com 2019 - 2024. All rights reserved.