I have some multi-threaded code that's giving me trouble. This is as simple as I can reproduce it:
use std::thread;
use std::time;
use std::sync::{Arc, atomic::{Ordering, AtomicBool}};
use std::ops::Drop;
struct Container {
// Join Handle for a thread
th: Option<thread::JoinHandle<()>>,
// Gets set to true when we want the thread to exit
stop_thread: Arc<AtomicBool>,
}
impl Container {
fn new() -> Self {
// Create new instance
let mut inst = Self {
th: None,
stop_thread: Arc::new(AtomicBool::new(false)),
};
let stop_thread = inst.stop_thread.clone();
// Start a new thread that does some work
let t = thread::spawn(move || {
// Keep doing work until stop_thread gets set to true
while !stop_thread.load(Ordering::SeqCst) {
println!("Doing stuff...");
thread::sleep(time::Duration::from_secs(1));
}
println!("Thread exited");
});
inst.th = Some(t);
inst
}
}
impl Drop for Container {
fn drop(&mut self) {
self.stop_thread.store(true, Ordering::SeqCst);
if let Some(t) = self.th {
t.join().unwrap();
}
}
}
fn main() {
let c = Container::new();
thread::sleep(time::Duration::from_secs(3));
drop(c);
}
The idea is that when a new instance of the Container struct is created, a background thread is started that does something. It keeps running until the instance is destroyed, at which point, I need the thread to be notified that it needs to exit. I also need to actually wait for the thread to exit before proceeding.
Everything works great, except for the code in the drop function. Rust is unhappy with if let Some(t) = self.th. It says:
error[E0507]: cannot move out of `self.th.0` which is behind a mutable reference
--> src/main.rs:45:26
|
45 | if let Some(t) = self.th {
| - ^^^^^^^ help: consider borrowing here: `&self.th`
| |
| data moved here
| move occurs because `t` has type `JoinHandle<()>`, which does not implement the `Copy` trait
Why can't I do this? What is self.th.0?
When I try to take Rust's suggestion, and do if let Some(t) = &self.th instead, it still doesn't compile:
error[E0507]: cannot move out of `*t` which is behind a shared reference
--> src/main.rs:46:13
|
46 | t.join().unwrap();
| ^ move occurs because `*t` has type `JoinHandle<()>`, which does not implement the `Copy` trait
What am I doing wrong?