将 `Var` 从 `Arc<Mutex<Var>>` 移出

Rah*_*ahn 9 multithreading rust

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());
}
Run Code Online (Sandbox Code Playgroud)

我正在定义一个要操作的多线程函数Var,但该函数无法编译并抱怨:

error[E0507]: cannot move out of a shared reference
Run Code Online (Sandbox Code Playgroud)

有没有办法停止共享shared_var并返回其中的变量?

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

rod*_*igo 19

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

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

1.我确信没有其他强有力的参考,这是最后一个Arc。如果没有,那就让它恐慌吧。

如果是这种情况,您可以使用来访问内部互斥锁。然后再获取真正的值。Arc::try_unwrap()Arc::into_inner()into_inner()

//let mutex = Arc::try_unwrap(shared_var).unwrap();
let mutex = Arc::into_inner(shared_var).unwrap();
mutex.into_inner().unwrap()
Run Code Online (Sandbox Code Playgroud)

请注意,为了使这些Result::unwrap()工作正常,您的类型必须实现Debug,因为......原因。如果没有,您可以使用一match/panic!对。

2.可能还有其他强引用的副本Arc,无论如何我都想窃取该对象。

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

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

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

3. 可能还有其他副本Arc,但我不想处理Option<Var>.

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

let mut lck = shared_var.lock().unwrap();
std::mem::take(&mut *lck)
Run Code Online (Sandbox Code Playgroud)

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

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

  • 还可以选择使用作用域线程,这使得“Arc”变得不必要。 (3认同)