use std::{ panic::{self, AssertUnwindSafe}, thread, }; pub struct ThreadPool { workers: Vec, sender: Option>, } type Job = Box; impl ThreadPool { pub fn new(size: usize, max_waiting: usize) -> Self { assert!(size > 0); let (sender, receiver) = crossbeam_channel::bounded(max_waiting); let mut workers = Vec::with_capacity(size); for id in 0..size { workers.push(Worker::new(id, receiver.clone())); } ThreadPool { workers, sender: Some(sender), } } pub fn execute(&self, f: F) where F: FnOnce() + Send + 'static, { let job = Box::new(f); if let Some(sender) = &self.sender { sender.send(job).unwrap(); } } } impl Drop for ThreadPool { fn drop(&mut self) { drop(self.sender.take()); // close channel for worker in &mut self.workers { if let Some(thread) = worker.thread.take() { thread.join().unwrap(); } } } } #[allow(unused)] struct Worker { id: usize, thread: Option>, } impl Worker { fn new(id: usize, receiver: crossbeam_channel::Receiver) -> Self { let thread = thread::spawn(move || { while let Ok(job) = receiver.recv() { let result = panic::catch_unwind(AssertUnwindSafe(job)); if let Err(e) = result { eprintln!("Worker {id} saw a panic: {e:?}"); } } }); Worker { id, thread: Some(thread), } } }