simple-http: Implement ThreadPool cleanup
[learn-rust.git] / simple-http / src / lib.rs
index ff8bc4f3f8f63faecf47626d0f3a1ecff1082902..3c5caa679a3e4525d3147585dde045a859b92e7d 100644 (file)
@@ -1,18 +1,42 @@
 use std::thread;
 use std::thread;
+use std::sync::{Arc, mpsc, Mutex};
+
+type Job = Box<dyn FnOnce() + Send + 'static>;
+
+enum Message {
+    NewJob(Job),
+    Terminate,
+}
 
 struct Worker {
     id: usize,
 
 struct Worker {
     id: usize,
-    thread: thread::JoinHandle<()>,
+    thread: Option<thread::JoinHandle<()>>,
 }
 
 impl Worker {
 }
 
 impl Worker {
-    fn new(id: usize) -> Worker {
-        Worker { id, thread: thread::spawn(|| {}) }
+    fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Message>>>) -> Worker {
+        let thread = Some(thread::spawn(move || loop {
+            let message = receiver.lock().unwrap().recv().unwrap();
+
+            match message {
+                Message::NewJob(job) => {
+                    println!("Worker {} got a job, executing", id);
+                    job();
+                },
+
+                Message::Terminate => {
+                    println!("Worker {} got terminated", id);
+                    break;
+                }
+            }
+        }));
+        Worker { id, thread }
     }
 }
 
 pub struct ThreadPool {
     workers: Vec<Worker>,
     }
 }
 
 pub struct ThreadPool {
     workers: Vec<Worker>,
+    sender: mpsc::Sender<Message>,
 }
 
 impl ThreadPool {
 }
 
 impl ThreadPool {
@@ -25,16 +49,35 @@ impl ThreadPool {
         assert!(size > 0);
         let mut workers = Vec::with_capacity(size);
 
         assert!(size > 0);
         let mut workers = Vec::with_capacity(size);
 
+        let (sender, receiver) = mpsc::channel();
+        let receiver = Arc::new(Mutex::new(receiver));
+
         for id in 0..size {
         for id in 0..size {
-            workers.push(Worker::new(id));
+            workers.push(Worker::new(id, Arc::clone(&receiver)));
         }
 
         }
 
-        ThreadPool { workers }
+        ThreadPool { workers, sender }
     }
 
     pub fn execute<F>(&self, f: F)
     where F: FnOnce() + Send + 'static
     {
     }
 
     pub fn execute<F>(&self, f: F)
     where F: FnOnce() + Send + 'static
     {
-        thread::spawn(f);
+        self.sender.send(Message::NewJob(Box::new(f))).unwrap();
+    }
+}
+
+impl Drop for ThreadPool {
+    fn drop(&mut self) {
+        for _ in &self.workers {
+            self.sender.send(Message::Terminate).unwrap();
+        }
+
+        for worker in &mut self.workers {
+            println!("Shutting down worker {}", worker.id);
+
+            if let Some(thread) = worker.thread.take() {
+                thread.join().unwrap();
+            }
+        }
     }
 }
     }
 }