如何从Arc <mutex <t>&gt;?</mutex <t>取得T的所有权

时间:2015-03-20 23:38:42

标签: rust

我想从受Mutex保护的函数返回一个值,但无法理解如何正确执行。此代码不起作用:

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

fn func() -> Result<(), String> {
    let result_my = Arc::new(Mutex::new(Ok(())));
    let result_his = result_my.clone();

    let t = std::thread::spawn(move || {
        let mut result = result_his.lock().unwrap();
        *result = Err("something failed".to_string());
    });

    t.join().expect("Unable to join thread");

    let guard = result_my.lock().unwrap();
    *guard
}

fn main() {
    println!("func() -> {:?}", func());
}

Playground

编译器抱怨:

error[E0507]: cannot move out of borrowed content
  --> src/main.rs:16:5
   |
16 |     *guard
   |     ^^^^^^ cannot move out of borrowed content

3 个答案:

答案 0 :(得分:9)

在Rust 1.15中,您可以使用Arc::try_unwrapMutex::into_inner

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

fn func() -> Result<(), String> {
    let result_my = Arc::new(Mutex::new(Ok(())));
    let result_thread = result_my.clone();

    let t = std::thread::spawn(move || {
        let mut result = result_thread.lock().unwrap();
        *result = Err("something failed".to_string());
    });

    t.join().expect("Unable to join threads");

    let lock = Arc::try_unwrap(result_my).expect("Lock still has multiple owners");
    lock.into_inner().expect("Mutex cannot be locked")
}

fn main() {
    println!("func() -> {:?}", func());
}

答案 1 :(得分:7)

我到目前为止找到的最佳解决方案是将结果包装成Option然后将其取出:

fn func() -> Result<(), String> {
    let result_my = Arc::new(Mutex::new(Some(Ok(()))));
    let result_his = result_my.clone();

    let t = std::thread::spawn(move || {
        let mut result = result_his.lock().unwrap();
        *result = Some(Err("something failed".to_string()));
    });

    t.join().expect("Unable to join thread");

    let mut guard = result_my.lock().unwrap();
    guard.take().unwrap()
}

似乎比mem::replace solution proposed by @SBSTP更好,因为无需为交换构建空T,并且它可以防止多次提取。

答案 2 :(得分:2)

您可以使用mem::replace来转移可变引用的所有权,方法是将其替换为新值。 (返回并移动旧值)

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

fn func() -> Result<(), String> {
    let result_my = Arc::new(Mutex::new(Ok(())));
    let result_his = result_my.clone();

    let t = std::thread::spawn(move || {
        let mut result = result_his.lock().unwrap();
        *result = Err("something failed".to_string());
    });

    t.join();

    let mut guard = result_my.lock().unwrap();
    mem::replace(&mut guard, Ok(()))
}

fn main() {
    println!("func() -> {:?}", func());
}