I am trying to run a thread in background and then change an AtomicBool to ask the thread to stop. To ensure the thread stopped properly, I want to call join
method of the JoinHandle.
Instead of calling join, if I just wait (thread::sleep_ms
) for sometime after setting the AtomicBool, the thread properly closes. But to ensure this I want to use join.
Or is there any better method to ensure the thread closed properly?
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::thread::JoinHandle;
struct MyInner { s: String }
struct My {
inner: Arc<Mutex<MyInner>>,
close_thread: Arc<AtomicBool>,
my_thread: JoinHandle<()>
}
impl MyInner {
fn new(s: String) -> MyInner {
MyInner {
s: s
}
}
}
impl My {
fn new(s: String) -> My {
My {
inner: Arc::new(Mutex::new(MyInner::new(s))),
close_thread: Arc::new(AtomicBool::new(false)),
my_thread: thread::spawn(move || {})
}
}
fn stop_thread(&self) {
self.close_thread.swap(true, Ordering::Relaxed);
// ERROR!
self.my_thread.join().expect("Couldn't join my_thread on the main thread");
}
fn start(&mut self) {
let local_self = self.inner.clone();
let close_thread = self.close_thread.clone();
self.my_thread = thread::spawn(move || {
loop {
if close_thread.load(Ordering::Relaxed) {
println!("Closing thread!");
return;
}
let gaurd = local_self.lock().unwrap();
println!("Local self has value: {}", (*gaurd).s);
std::mem::drop(gaurd);
thread::sleep_ms(1000);
}
});
}
}
fn main() {
let mut m = My::new("blo".to_owned());
m.start();
thread::sleep_ms(2000);
m.stop_thread();
println!("Complete!");
}
For the above code, I get the error:
error[E0507]: cannot move out of `self.my_thread` which is behind a shared reference
--> src/main.rs:35:9
|
35 | self.my_thread.join().expect("Couldn't join my_thread on the main thread");
| ^^^^^^^^^^^^^^ move occurs because `self.my_thread` has type `std::thread::JoinHandle<()>`, which does not implement the `Copy` trait
I also tried using Arc
on the JoinHandle but even after Arc::clone
I get the same error.