changeset 86:ab08b4bcd4a9

Attempt at the "Barber Shop problem" in Clojure This generally seems to work. The code doesn't fail, and often everyone gets a hair cut (because the barber takes 20ms and people arrive, on average, every 20ms). But sometimes people walk away, or the barber is mid-cut (because of the initial delay).
author IBBoard <dev@ibboard.co.uk>
date Sat, 15 Jun 2019 14:37:47 +0100
parents 67e2bb3bcccd
children 2b5341fc4555
files 6-Clojure/barbershop.clj
diffstat 1 files changed, 46 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/6-Clojure/barbershop.clj	Sat Jun 15 14:37:47 2019 +0100
@@ -0,0 +1,46 @@
+(def barber (agent 0))
+(def customer_queue (ref 0))
+
+(defn output [& args]
+    (println (System/currentTimeMillis) (clojure.string/join " " args)))
+
+(defn cut_hair [the_barber queue customer]
+    (dosync
+        (commute queue dec)
+    )
+    (output customer "Bzzzzz…")
+    (Thread/sleep 20)
+    (output customer "…zzzzzzz")
+    (inc the_barber)
+)
+
+(defn enqueue_customer [the_barber queue customer]
+    (dosync
+        (if (< @queue 3)
+            (do
+                (commute queue inc) ; We *should* be okay using commut because we deref in the IF, which should commit all previous edits. We don't care about the value right now.
+                (output customer "sat in queue")
+                (send-off the_barber cut_hair queue customer) ; At some point, the barber will cut their hair
+            )
+            (output customer " walked away"); Else they walk away
+        )
+    )
+)
+
+(def min_interval 10)
+(def max_count 100)
+(def duration (* max_count  min_interval))
+(output "Spawn customers")
+(future
+    (doseq [customer (range max_count)]  ; Max number of customers is if they arrive at shortest interval
+        (let [delay (+ min_interval (rand-int 21))]      ; Note: (rand-int 21) to get 10 to 30 inclusive
+            (Thread/sleep delay)
+            (output customer "arrived after " delay "ms")
+            (future (enqueue_customer barber customer_queue customer))
+        )
+    )
+)
+(output "Awaiting completion")
+(Thread/sleep duration)
+(println @barber "customers got haircuts in" (/ duration 1000) "seconds")
+(shutdown-agents)