I am trying to allow multiple threads to mutate the same variable using Arc and a Mutex lock, but it seems as though I am unable to get ownership of the variable, even after cloning it?
// modifed example from https://doc.rust-lang.org/beta/rust-by-example/std/arc.html
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
fn main() {
// This variable declaration is where its value is specified.
let test = Arc::new(Mutex::new(TestStruct{
counter: 0,
}));
println!("Initial Counter Value: 0");
for _ in 0..10 {
// Here there is no value specification as it is a pointer to a
// reference in the memory heap.
let test = Arc::clone(&test);
thread::spawn(move || {
// As Arc was used, threads can be spawned using the value allocated
// in the Arc variable pointer's location.
test.lock().unwrap().increment();
});
}
// Make sure all Arc instances are printed from spawned threads.
thread::sleep(Duration::from_secs(1));
println!("Final Counter Value: {:?}", test.lock().unwrap().counter);
}
#[derive(Debug)]
struct TestStruct {
// counter
counter: i32,
}
impl TestStruct {
// increment counter
fn increment(mut self) {
self.counter =1;
}
}
I keep getting errors that say error[E0507]: cannot move out of dereference of "MutexGuard<"_, TestStruct>
anywhere that I try to access the variable with test.lock().unwrap()
All I am trying to do in this example is increment a counter from multiple threads, and then check the value of this counter afterwards.
I've gotten it to work by placing the value inside of an option: Arc::new(Mutex::new(Some(TestStruct{..})))
and then taking the value from that option: test.lock().unwrap().take()
, but taking the value out of the Option then replaces it with None, so it only works once.
Does anyone know what I am doing wrong / how I might be able to get this to work?
Here is a link to a playground with the code.
CodePudding user response:
Since you take mut self
as opposed to &mut self
in increment you need to exclusively own the variable to use it.
But you can only take references to objects in Arc<Mutex<…>>
.
You probably want to take self
by mutable reference in increment
instead:
impl TestStruct {
// increment counter
fn increment(&mut self) {
self.counter =1;
}
}