我有一个应该在多个线程中传递的结构。其结构如下:
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 到相应的元素)。
您能在这里帮助我并就如何有效解决该问题提供一些建议吗?谢谢你。
您无法从锁中获得简单的参考。即使在嵌套锁情况之外,这也不起作用:
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) { ... }