Home > Software design >  Rust: Using Mutex and Arc to mutate
Rust: Using Mutex and Arc to mutate

Time:01-26

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;
    }
}
  • Related