I'm trying to share a mutable object between threads in Rust using Arc
, but I get this error:
error[E0596]: cannot borrow data in a `&` reference as mutable
--> src/main.rs:11:13
|
11 | shared_stats_clone.add_stats();
| ^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
This is the sample code:
use std::{sync::Arc, thread};
fn main() {
let total_stats = Stats::new();
let shared_stats = Arc::new(total_stats);
let threads = 5;
for _ in 0..threads {
let mut shared_stats_clone = shared_stats.clone();
thread::spawn(move || {
shared_stats_clone.add_stats();
});
}
}
struct Stats {
hello: u32,
}
impl Stats {
pub fn new() -> Stats {
Stats { hello: 0 }
}
pub fn add_stats(&mut self) {
self.hello += 1;
}
}
What can I do?
Arc
's documentation says:You will likely want a
Mutex
combined with anArc
:This is largely cribbed from the
Mutex
documentation.As of Rust 1.15, it's possible to get the value back. See my additional answer for another solution as well.
Because I got confused! :-)
In the example code, the result of
thread::spawn
(aJoinHandle
) is immediately dropped because it's not stored anywhere. When the handle is dropped, the thread is detached and may or may not ever finish. I was confusing it withJoinGuard
, a old, removed API that joined when it is dropped. Sorry for the confusion!For a bit of editorial, I suggest avoiding mutability completely:
Here, we keep a reference to the
JoinHandle
and then wait for all the threads to finish. We then collect the results and add them all up. This is the common map-reduce pattern. Note that no thread needs any mutability, it all happens in the master thread.