Goal and environment
I have been following the book, and wanted to share a Vec between threads so that some integers are pushed into it in somewhat arbitrary order. I tried Vec, Arc, Mutex for this.
The environment I am using is
OS: MacOS 12.5.1 on M1 chip
Shell: zsh 5.8.1 (x86_64-apple-darwin21.0)
Compiler: rustc 1.64.0 (a55dd71d5 2022-09-19)
Cargo: cargo 1.64.0 (387270bc7 2022-09-16)
Code tested
Here is my code.
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let contents = Arc::new(Mutex::new(vec![]));
for i in 0..10 {
let contents = Arc::clone(&contents);
thread::spawn(move || {
let mut contents = contents.lock().unwrap();
contents.push(i);
});
}
println!("Contents: {:?}", contents);
}
Result & expected
I expected all 10 integers to be in contents
, albeit random order.
However the result sometimes missses some integers, as follows.
thread % for i in $(seq 0 10); do target/debug/thread; done
Contents: Mutex { data: [0, 1, 2, 3, 4, 5, 6, 7, 8], poisoned: false, .. }
Contents: Mutex { data: [0, 1, 2, 4, 6, 3, 5, 8], poisoned: false, .. }
Contents: Mutex { data: <locked>, poisoned: false, .. }
Contents: Mutex { data: [0, 1, 2, 4, 3, 5, 6, 7, 8], poisoned: false, .. }
Contents: Mutex { data: [0, 1, 2, 3, 5, 4, 6, 7, 8], poisoned: false, .. }
Contents: Mutex { data: [0, 1, 2, 3, 4, 5, 7, 6], poisoned: false, .. }
Contents: Mutex { data: [0, 2, 4, 6, 1, 7], poisoned: false, .. }
Contents: Mutex { data: [0, 1, 2, 3, 5, 4, 6, 7, 8], poisoned: false, .. }
Contents: Mutex { data: [0, 1, 2, 3, 4, 5, 6, 7, 8], poisoned: false, .. }
Contents: Mutex { data: [0, 1, 3, 2, 5, 6, 7, 8, 4], poisoned: false, .. }
Contents: Mutex { data: [0, 1, 2, 3, 4, 5, 6, 7, 8], poisoned: false, .. }
I thought Vec::push might take so long that it sometimes does not finish even after the Mutex goes out of scope, and added short sleep at the end of the closure, as follows.
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
fn main() {
let contents = Arc::new(Mutex::new(vec![]));
for i in 0..10 {
let contents = Arc::clone(&contents);
thread::spawn(move || {
let mut contents_local = contents.lock().unwrap();
contents_local.push(i);
thread::sleep(Duration::from_millis(1000));
});
}
println!("Contents: {:?}", contents.lock().unwrap());
}
However the problem persists. As sleeps of 1, 10 ms did not help, I tried with 1 second in each thread but still, some of the integers are missed, as follows.
thread % for i in $(seq 0 10); do target/debug/thread; done
Contents: [0, 1, 2, 3, 4, 5, 6, 7, 8]
Contents: [0, 1, 2, 4, 3, 5, 6, 7, 8]
Contents: [0, 1, 2, 3, 4, 5, 6, 7, 8]
Contents: [0, 1, 2, 3, 4, 5, 6, 7, 8]
Contents: [0, 1, 3, 2, 4, 5, 6, 7, 8]
Contents: [0, 1, 3, 2, 4, 5, 6, 7]
Contents: [0, 1, 2, 3, 4, 5, 6, 7, 8]
Contents: [0, 1, 2, 3, 4, 5, 6, 7, 8]
Contents: [0, 1, 3, 4, 2, 5, 6, 7, 8]
Contents: [1, 0, 3, 5, 4, 2, 6, 7]
Contents: [0, 1, 3, 2, 4, 6, 5, 7]
Due diligence
I wanted to resolve the issue myself but I have been unable to search for relevant problems, particularly for a novice like me. I have searched google and this forum for some combinations of sync, vec, mutex, thread-safe with no success yet. Any link may be of help to me.