【问题标题】:Arc lifetime does not live long enough from clone()从 clone() 开始,弧的生命周期不够长
【发布时间】:2016-09-19 16:22:43
【问题描述】:

我正在尝试创建一个可能在线程之间共享的参数结构。它有一个名为layer_storage 的成员,一些成员需要对其进行变异。我尝试了以下代码,但收到一条错误消息,指出克隆的 Arc 寿命不够长。在添加 Arc<Mutex<>> 之前,同一成员工作正常。

use std::sync::{Arc, Mutex};

#[derive(Clone)]
pub struct Params {
    pub optional: Vec<f32>,
}

pub struct ParamManager {
    layer_storage: Arc<Mutex<Vec<Params>>>,
}

impl Default for ParamManager {
    fn default() -> ParamManager {
        ParamManager {
            layer_storage: Arc::new(Mutex::new(vec![Params { optional: vec![1.0f32, 2.0f32] },
                                                    Params { optional: vec![3.0f32, 4.0f32] }])),
        }
    }
}

impl ParamManager {
    pub fn get_mut_params(&mut self, layer_index: usize) -> &mut Params {
        let layers_arc = self.layer_storage.clone();
        let layers = layers_arc.get_mut().unwrap();
        // tried this initially:
        // let layers = self.layer_storage.clone().get_mut().unwrap();
        assert!(layers.len() - 1 >= layer_index);
        &mut layers[layer_index]
    }
}

fn main() {
    let mut bla = ParamManager::default();
    let i = bla.get_mut_params(0);
}

(Playground)

【问题讨论】:

  • 您是否尝试将克隆分配给一个变量,然后在单独的语句中执行其余部分?
  • 是的,这就是我所做的:self.layer_storage.clone(),然后将其作为变量使用。

标签: thread-safety rust


【解决方案1】:

正如@Shepmaster 所说,您不能只从get_mut_params 返回对Arc&lt;Mutex&lt;T&gt;&gt; 中某些内容的引用;这是您从他们那里得到的保证之一!

在可能的情况下可行的一种解决方案是将函数翻转过来;而不是返回一个可变引用,取一个给定可变引用的闭包:

impl ParamManager {
    pub fn with_mut_params<F>(&mut self, layer_index: usize, mut f: F)
                     where F: FnMut(&mut Params) {
        let layers_arc = self.layer_storage.clone();
        let layers = layers_arc.lock().unwrap();
        f(&mut layers[layer_index]);
    }
}

fn main() {
    let mut bla = ParamManager::default();

    // Context used by the closure
    let some_var: i32 = 7;
    let other_var: mut MyContext = do_something();

    bla.with_mut_params(0, |i| {
       // do stuff with i
       ...
       // A closure has access to surrounding variables
       other_var.foo(i, some_var);
    });

}

【讨论】:

  • 谢谢,这是处理问题的一种非常优雅的方式。我在这里看到的唯一问题是通用性:即闭包只接受一个参数。如果需要某些上下文,这可能也无法正常工作(尤其是因为 rust 没有重载)。
  • 作为一个闭包而不仅仅是一个函数指针意味着它可以包含上下文。你能举个例子说明什么是不可能的吗?
  • 既然你有where F: FnMut(&amp;mut Params),唯一可接受的关闭类型就是只接收&amp;mut Params,对吗?假设一个函数需要一些,例如:where F: FnMut(&amp;mut Params) and 其中F: FnMut(&amp;mut Params, &amp;MyContext, i32) 它需要两个不同的重载操作,这是不可能的(没有一堆Optional&lt;&gt;有点丑
  • 我将编辑我的答案以展示闭包如何解决这个问题,因为评论太短了。
  • 我想我意识到了!从锈书快速阅读。它还考虑了本地范围!
【解决方案2】:

我认为编译器适合您的情况。

这里有两个明显的错误:

  1. layers_arc 值一直存在到块结束,然后它的析构函数将递减引用计数器并可能删除整个值。或者它可以随时被放到其他线程中。所以返回指向其内容的指针是非法的。

  2. Mutex::get_mut方法需要&amp;mut self,而直接从Arc获取是不可能的。

所以你必须以某种方式重构你的代码。例如,您可以使用 Arc&lt;Mutex&gt; 保护向量中的每个单独项目,并使用 .clone() 按值返回它们。

【讨论】:

  • 谢谢@swizard。这也是一个有效的答案。只是为了清洁决定选择下面的那个。
猜你喜欢
  • 2018-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-07
  • 1970-01-01
  • 1970-01-01
  • 2019-04-28
  • 2021-06-18
  • 1970-01-01
相关资源
最近更新 更多