How to move the content of Mutex wrapped by Arc

Please consider the following example:

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

fn main() {
	let w_vec = Arc::new(Mutex::new(vec![1, 2, 3]));
	let v = w_vec.lock().unwrap();
	print(*v);
}

fn print(v: Vec<i32>) {
	println!("{:?}", v);
}

I got the following error:

error[E0507]: cannot move out of borrowed content
 --> src/main.rs:7:8
  |
7 | 	print(*v);
  | 	      ^^ cannot move out of borrowed content

error: aborting due to previous error

error: Could not compile `blah`. 

rustc --version: rustc 1.16.0 (30cf806ef 2017-03-10)

You can’t “move out” of that. It would mean w_vec is invalid state.

You can either make print take a reference: fn print(v : &[i32]) and call it as print(v.as_slice()) or if you really want to move out the stuff from w_vec use https://doc.rust-lang.org/std/mem/fn.replace.html to substitute it with a new vec, so that w_vec state is valid.

If the compiler let you do this directly, then the next caller to lock the mutex would see undefined memory.

But both types have ways to move by proving you’re the sole owner. Arc::try_unwrap will attempt this, succeeding only if the reference count is 1 (just you). Then Mutex::into_inner can move from that into the inner content.

2 Likes

it worked using let v = Arc::try_unwrap(w_vec).unwrap().into_inner().unwrap();
thank you @cuviper

As far as I can see you don’t need to move the content out of the Arc. Instead you can pass the vector to print by reference. This version of the code allows you to print the vector more than once.

fn main() {
    ....
    print(v);
}

fn print(v: &Vec<i32>) {
    println!("{:?}", *v);
}
    // with a copy 
let built_words: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![]));
let result: Vec<String> = built_words.lock().unwrap().clone();

// using drain 
let mut locked_result = built_words.lock().unwrap();
let mut result: Vec<String> = vec![];
result.extend(locked_result.drain(..));

Please wrap your code with a code fence:

```
Your code
```

Please refrain from replying directly to a very old topic; instead create a new topic which links to this one if you have questions.


What you have posted does not "move out" of the Arc<Mutex>, and instead clones the data. The intended way to move out of an Arc<Mutex<T>> is to use the following methods:

let x = Arc::new(Mutex::new(Vec::<()>::new()));
let w = Arc::try_unwrap(x).unwrap().into_inner().unwrap();

Since these ensure that both:

  • The Arc has no other strong references
  • The Mutex is not poisoned.

Thanks! I did

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.