1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
use std::sync::mpsc; use std::sync::mpsc::TryRecvError; use std::sync::Arc; use std::sync::Mutex; use std::thread; use std::thread::JoinHandle; use log::info; #[derive(Default)] pub struct Worker { cancellation: Option<mpsc::Sender<()>>, } impl Worker { pub fn run<F, T>(&mut self, func: F) -> JoinHandle<T> where F: 'static + Send + FnOnce(Cancel) -> T, T: 'static + Send, { if let Some(cancellation) = self.cancellation.as_mut() { info!("asking existing worker to cancel"); let _ = cancellation.send(()); } let (cancellation, done) = mpsc::channel(); self.cancellation = Some(cancellation); thread::spawn(move || func(Cancel::OnMessage(Arc::new(Mutex::new(done))))) } } pub enum Cancel { OnMessage(Arc<Mutex<mpsc::Receiver<()>>>), Never, } impl Cancel { pub fn check_done(&self) -> bool { match self { Cancel::OnMessage(done) => match done.lock().unwrap().try_recv() { Ok(()) | Err(TryRecvError::Disconnected) => true, Err(TryRecvError::Empty) => false, }, Cancel::Never => false, } } pub fn maybe_abort(&self) { assert!(!self.check_done()) } }