simple-http: Implement ThreadPool messaging
[learn-rust.git] / simple-http / src / lib.rs
1 use std::thread;
2 use std::sync::{Arc, mpsc, Mutex};
3
4 type Job = Box<dyn FnOnce() + Send + 'static>;
5
6 struct Worker {
7     id: usize,
8     thread: Option<thread::JoinHandle<()>>,
9 }
10
11 impl Worker {
12     fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Job>>>) -> Worker {
13         let thread = Some(thread::spawn(move || loop {
14             let job = receiver.lock().unwrap().recv().unwrap();
15             println!("Worker {} got a job, executing", id);
16             job();
17         }));
18         Worker { id, thread }
19     }
20 }
21
22 pub struct ThreadPool {
23     workers: Vec<Worker>,
24     sender: mpsc::Sender<Job>,
25 }
26
27 impl ThreadPool {
28     /// Create a new thread pool.
29     ///
30     /// # Panics
31     ///
32     /// - if size is zero
33     pub fn new(size: usize) -> ThreadPool {
34         assert!(size > 0);
35         let mut workers = Vec::with_capacity(size);
36
37         let (sender, receiver) = mpsc::channel();
38         let receiver = Arc::new(Mutex::new(receiver));
39
40         for id in 0..size {
41             workers.push(Worker::new(id, Arc::clone(&receiver)));
42         }
43
44         ThreadPool { workers, sender }
45     }
46
47     pub fn execute<F>(&self, f: F)
48     where F: FnOnce() + Send + 'static
49     {
50         self.sender.send(Box::new(f)).unwrap();
51     }
52 }
53
54 impl Drop for ThreadPool {
55     fn drop(&mut self) {
56         for worker in &mut self.workers {
57             println!("Shutting down worker {}", worker.id);
58
59             if let Some(thread) = worker.thread.take() {
60                 thread.join().unwrap();
61             }
62         }
63     }
64 }