【问题标题】:Move `Var` out from `Arc<Mutex<Var>>`将 `Var` 从 `Arc<Mutex<Var>>` 移出
【发布时间】:2022-01-16 20:35:04
【问题描述】:
use std::ops::Deref;
use std::sync::{Arc, Mutex, MutexGuard};

struct Var {}

fn multithreading() -> Var {
    let shared_var = Arc::new(Mutex::new(Var {}));
    /*
    multithreading job
     */

    return *(shared_var.lock().unwrap().deref());
}

我正在定义一个多线程函数来对Var 进行操作,但该函数无法编译和投诉:

error[E0507]: cannot move out of a shared reference

有什么办法可以停止shared_var的共享并返回其中的变量?

Var 实现特征Copy 也可以解决错误,但在我的实际用例中Var 太大而无法复制,我更喜欢任何其他解决方案。

【问题讨论】:

  • 请记住,在机器代码级别,移动本质上是复制。如果您避免制作“复制”类型的动机是它的大小,那么您可能需要重新考虑您的整体设计。

标签: multithreading rust


【解决方案1】:

这里的问题是,如果你从共享变量中删除你的Var,那里会留下什么?如果您的 Arc 的任何其他副本留在某处并尝试访问现在已删除的对象,会发生什么情况?

这个问题有几个可能的答案:

1。我很确定没有其他强有力的参考,这是最后一个Arc。如果没有,让它恐慌。

如果是这种情况,您可以使用Arc::try_unwrap() 来访问内部互斥体。然后另一个into_inner() 得到真正的价值。

let mutex = Arc::try_unwrap(shared_var).unwrap();
mutex.into_inner().unwrap()

请注意,要使这些Result::unwrap() 工作,您的类型必须实现Debug,对于... reasons。如果没有,您可以使用match/panic! 对。

2。 Arc 可能还有其他强引用副本,反正我想偷对象。

然后你必须把一些东西放在它的位置。显而易见的解决方案是存储 Option&lt;Var&gt; 并使用 Option::take() 窃取值:

let shared_var = Arc::new(Mutex::new(Some(Var {})));
/*
  multithreading job
*/
let mut lck = shared_var.lock().unwrap();
lck.take().unwrap()

现在,此共享值的任何其他用途都必须检查该选项,以防出现None

3。 Arc 可能还有其他副本,但我不想处理 Option&lt;Var&gt;

但是你必须在那儿留下一些东西!也许您可以在其位置插入一个虚拟对象。如果你的Var 实现了Default,你可以使用std::mem::take()

let mut lck = shared_var.lock().unwrap();
std::mem::take(&mut *lck)

如果它没有实现Default,但您可以廉价地创建一个空对象,请改用std::mem::replace()

let mut lck = shared_var.lock().unwrap();
std::mem::replace(&mut *lck, Var{})

【讨论】:

  • 还有使用作用域线程的选项,这使得Arc变得不必要。
  • 你也可以使用make_mut()然后try_unwrap()
  • "请注意,要使这些 Result::unwrap() 工作,您的类型必须实现调试,原因...原因。“您确定吗?从问题的答案看来,需要实现调试的是类型“E”(错误),而不是类型“T”(数据)。
  • @plugwash:嗯,是的,但是如果你看一下函数的定义:pub fn try_unwrap(this: Arc&lt;T&gt;) -&gt; Result&lt;T, Arc&lt;T&gt;&gt;,错误类型实际上是Arc&lt;T&gt;,而implements Debug if T implements Debug
  • @ChayimFriedman:但是Arc::make_mut()要求TClone,OP说值太大,无法复制。
猜你喜欢
  • 2017-03-28
  • 2018-11-22
  • 1970-01-01
  • 2015-10-24
  • 1970-01-01
  • 2023-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多