I want to return a value from a function which is protected by a Mutex
, but cannot understand how to do it properly. This code does not work:
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
The compiler complains:
error[E0507]: cannot move out of borrowed content
--> src/main.rs:16:5
|
16 | *guard
| ^^^^^^ cannot move out of borrowed content
An RAII guard is returned to allow scoped unlock of the lock. When the guard goes out of scope, the mutex will be unlocked.
'Arc' stands for 'Atomically Reference Counted'. The type Arc<T> provides shared ownership of a value of type T , allocated in the heap. Invoking clone on Arc produces a new Arc instance, which points to the same allocation on the heap as the source Arc , while increasing a reference count.
Mutexes Allow Access to Data from One Thread at a Time. A mutex is an abbreviation for “mutual exclusion,” as in, it only allows one thread to access some data at any given time. To access the data in a mutex, a thread must first signal that it wants access by asking to acquire the mutex's lock.
An integer the size of which is arch will be 32 bits on an x86 machine and 64 bits on an x64 machine.
In Rust 1.15, you can use Arc::try_unwrap
and Mutex::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());
}
RwLock::into_inner
also exists since Rust 1.6.
The best solution I found so far is to wrap the result into an Option
and then take it out:
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()
}
It seems better than the mem::replace
solution proposed by @SBSTP because there is no need to construct an empty T
for swapping, and it prevents multiple extractions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With