1use std::sync::{mpsc, Arc, Mutex};
2use std::thread;
3
4type Job = Box<dyn FnOnce() + Send + 'static>;
5
6enum Message {
7 NewJob(Job),
8 Terminate,
9}
10
11pub struct ThreadPool {
12 workers: Vec<Worker>,
13 sender: Option<mpsc::Sender<Message>>,
14}
15
16const EMPTY_WORKERS: Vec<Worker> = Vec::new();
17pub const EMPTY_POOL: ThreadPool = ThreadPool::empty();
18
19impl ThreadPool {
20 pub fn new(size: usize) -> ThreadPool {
28 assert!(size > 0);
29
30 let (sender, receiver) = mpsc::channel();
31 let receiver = Arc::new(Mutex::new(receiver));
32
33 let mut workers = Vec::with_capacity(size);
34
35 for id in 0..size {
36 workers.push(Worker::new(id, Arc::clone(&receiver)));
37 }
38
39 ThreadPool {
40 workers,
41 sender: Some(sender),
42 }
43 }
44
45 pub const fn empty() -> Self {
46 ThreadPool {
47 workers: EMPTY_WORKERS,
48 sender: None,
49 }
50 }
51
52 pub fn execute<F>(&self, f: F)
53 where
54 F: FnOnce() + Send + 'static,
55 {
56 let job = Box::new(f);
57 if let Some(s) = &self.sender {
58 s.send(Message::NewJob(job)).unwrap();
59 }
60 }
61}
62
63impl Drop for ThreadPool {
64 fn drop(&mut self) {
65 for _ in &self.workers {
66 if let Some(s) = &self.sender {
67 s.send(Message::Terminate).unwrap();
68 }
69 }
70
71 for worker in &mut self.workers {
72 if let Some(thread) = worker.thread.take() {
73 thread.join().unwrap();
74 }
75 }
76 }
77}
78
79pub struct Worker {
80 pub id: usize,
81 thread: Option<thread::JoinHandle<()>>,
82}
83
84impl Worker {
85 fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Message>>>) -> Worker {
86 let thread = thread::spawn(move || loop {
87 let message = receiver.lock().unwrap().recv().unwrap();
88
89 match message {
90 Message::NewJob(job) => {
91 job();
93 }
94 Message::Terminate => {
95 break;
97 }
98 }
99 });
100
101 Worker {
102 id,
103 thread: Some(thread),
104 }
105 }
106}