试图从RwLock返回引用,“借来的价值活得不够长”错误 [英] Trying to return reference from RwLock, "borrowed value does not live long enough" Error

查看:305
本文介绍了试图从RwLock返回引用,“借来的价值活得不够长”错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近一直在研究我的第一个Rust项目,但遇到了困难。我正在使用 HashMap 映射字符串 s到 AtomicUsize 整数。 HashMap 受到 RwLock 的保护,以允许并发访问。我希望能够在 HashMap 中返回对 AtomicUsize 值的引用,但是如果我尝试返回这些引用给调用者过了 RwLockWriteGuard 的生命期后,我得到一个错误:借用的值不够长。。我已经复制了下面的一个简单例子,并在Rust游戏场上放置了相同的示例这里

 使用std :: collections :: HashMap; 
使用std :: sync :: RwLock;
使用std :: sync :: atomic :: {AtomicUsize,Ordering};

struct Bar {
val:AtomicUsize
}

impl Bar {
pub fn new() - > Self {
Bar {val:AtomicUsize :: new(0)}
}
}

struct Foo {
map:RwLock< HashMap< String ,Bar>>


$ b $ impl Foo {
pub fn get(& self,key:String) - > & Bar {
self.map.write()。unwrap()。entry(key).or_insert(Bar :: new())
}
}

fn main(){
let foo = Foo {map:RwLock :: new(HashMap :: new())};
let bar = foo.get(key.to_string());

我得到的错误发生在行上:

  self.map.write()。unwrap()。entry(key).or_insert(Bar :: new())

这是因为借入的价值不够长。我读过几篇讨论这个错误的文章,这篇特别重要。读完它后,我可以得知,互斥量返回的值必须小于互斥量,这似乎完全排除了我正在尝试执行的操作。我可以看到为什么这是不可能的,因为如果我们有一个指向Hashmap的指针,另一个将值插入互斥量中导致它被调整大小,那么我们将有一个悬挂指针。

然后我的问题是双重的。首先,我只是好奇,如果我正确地理解了这个问题,或者是否有另一个原因让我不能做我想做的事情?我的第二个问题是,如果没有 Box 原子整数并将其存储在 HashMap ?这样的方法似乎应该适用于我,因为我们可以返回一个指向 Boxed 值的指针,该值始终有效。然而,这种方法似乎效率不高,因为它需要额外的指针间接层和额外的分配。谢谢!

你是对的,你不能返回超过 MutexGuard ,因为那会导致一个可能悬空的指针。 一个 Box 是一个拥有的指针,除了重定向之外,就参考生命周期而言,它的行为就像包含的值一样。毕竟,如果您返回了对它的引用,其他人可能会将其从 HashMap 中移除并取消分配。



根据您想要对引用做什么,我可以考虑几个选项:


  1. Box 将这些值包装在 Arc 中。从 HashMap 中取出时,您可以克隆 Arc ,并且多个引用可以同时存在。


  2. 您也可以返回 MutexGuard 以及参考;请参阅这个问题,如果你只是想操作这个值,然后相对较快地删除参考,那么这个问题就可以很好地工作。这将保持互斥锁一直持续到你完成它。



I've been working on my first Rust project recently but have hit a snag. I am using a HashMap mapping Strings to AtomicUsize integers. The HashMap is protected by a RwLock to allow for concurrent access. I would like to be able to return references to AtomicUsize values in the HashMap, however if I try to return these references to the caller past the lifetime of the RwLockWriteGuard I get an error that borrowed value does not live long enough. I've reproduced a minimal example below and put the same example on the Rust playground here.

use std::collections::HashMap;
use std::sync::RwLock;
use std::sync::atomic::{AtomicUsize, Ordering};

struct Bar {
    val: AtomicUsize
}

impl Bar {
    pub fn new() -> Self {
        Bar { val: AtomicUsize::new(0) }
    }
}

struct Foo {
    map: RwLock<HashMap<String, Bar>>
}


impl Foo {
    pub fn get(&self, key: String) -> &Bar {
        self.map.write().unwrap().entry(key).or_insert(Bar::new())
    }
}

fn main() {
    let foo = Foo {map: RwLock::new(HashMap::new())};
    let bar = foo.get("key".to_string());
}

The error I get occurs on the line:

self.map.write().unwrap().entry(key).or_insert(Bar::new())

And is because the borrowed value does not live long enough. I've read a few other posts that discuss this error, this one in particular was especially relevant. After reading it over, I can gather that a value returned from a mutex must have a lifetime less than that of the mutex, which would seem to rule out completely what I'm trying to do. I can see why this should be impossible, because if we have a pointer into the Hashmap and another inserts values into the mutex which cause it to be resized, then we will have a dangling pointer.

My question, then, is twofold. Firstly, I'm just curious if I understand the problem correctly or if there is another reason why I'm disallowed from doing what I tried to do? And my second question is if there is perhaps another way to accomplish what I am trying to do without Box the atomic integers and storing those in the HashMap? Such an approach seems like it should work to me because we can return a pointer to the Boxed value which would always be valid. However it seems like this approach would be inefficient because it would require an extra layer of pointer indirection and an extra allocation. Thanks!

解决方案

You're correct that you can't return a reference to something which outlives the MutexGuard, because that would lead to a possibly dangling pointer.

Wrapping the contents in a Box won't help, though! A Box is an owned pointer and apart from the redirection behaves like the contained value as far as reference lifetime goes. After all, if you returned a reference to it, someone else might remove it from the HashMap and de-allocate it.

Depending on what you want to do with the reference, I can think of a couple of options:

  1. Instead of Boxing the values, wrap them in Arc. You would clone the Arc when taking from the HashMap, and multiple references can live at the same time.

  2. You could also return the MutexGuard along with the reference; see this question, which would work well if you just want to operate on the value and then drop the reference relatively soon. This would keep the mutex held until you're finished with it.

这篇关于试图从RwLock返回引用,“借来的价值活得不够长”错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆