blunders_engine/
threads.rs1use std::process;
4use std::sync::mpsc::{self, Receiver, Sender};
5use std::sync::{Arc, Mutex};
6use std::thread::{self, JoinHandle};
7
8pub struct PoisonPill;
13
14impl Drop for PoisonPill {
15 fn drop(&mut self) {
16 if thread::panicking() {
17 process::exit(1);
18 }
19 }
20}
21
22type Job = Box<dyn FnOnce() + Send + 'static>;
24
25enum Message {
27 NewJob(Job),
28 Terminate,
29}
30
31#[derive(Debug)]
33struct Thread {
34 pub id: usize,
35 pub name: String,
36 handle: Option<JoinHandle<()>>,
37}
38
39impl Thread {
40 fn new(id: usize, receiver: Arc<Mutex<Receiver<Message>>>) -> Self {
42 let runner = move || {
43 let _poison = PoisonPill;
45
46 loop {
47 let recv_result = { receiver.lock().unwrap().recv() };
48
49 match recv_result {
50 Ok(message) => match message {
51 Message::NewJob(job) => {
52 job();
53 }
54 Message::Terminate => break,
55 },
56
57 Err(_) => break,
59 }
60 }
61 };
62
63 let name = format!("Thread {}", id);
64 let handle = thread::Builder::new()
65 .name(name.clone())
66 .spawn(runner)
67 .unwrap();
68
69 Self {
70 id,
71 name,
72 handle: Some(handle),
73 }
74 }
75}
76
77impl Drop for Thread {
78 fn drop(&mut self) {
79 let handle_opt = self.handle.take();
80 if let Some(handle) = handle_opt {
81 let _ = handle.join();
82 }
83 }
84}
85
86#[derive(Debug)]
94pub struct ThreadPool {
95 num_threads: usize,
96 threads: Vec<Thread>,
97 sender: Sender<Message>,
98 receiver: Arc<Mutex<Receiver<Message>>>,
99}
100
101impl ThreadPool {
102 pub fn new(num_threads: usize) -> Self {
104 let (sender, receiver) = mpsc::channel::<Message>();
105 let receiver = Arc::new(Mutex::new(receiver));
106
107 let mut threads = Vec::with_capacity(num_threads);
108
109 for id in 0..num_threads {
110 threads.push(Thread::new(id, Arc::clone(&receiver)));
111 }
112
113 Self {
114 num_threads,
115 threads,
116 sender,
117 receiver,
118 }
119 }
120
121 pub fn run<J: Into<Job>>(&self, job: J) {
123 self.sender.send(Message::NewJob(job.into())).unwrap()
124 }
125}
126
127impl Drop for ThreadPool {
128 fn drop(&mut self) {
129 {
131 let locked_receiver = self.receiver.lock().unwrap();
132 while let Ok(_) = locked_receiver.try_recv() {}
133 }
134
135 for _ in 0..self.num_threads {
137 let _ = self.sender.send(Message::Terminate);
138 }
139 }
140}