I am very new to Clojure and I have been struggling to implement some parallel code. I found this code on the Internet. There is a warning that this is not the right way to do concurrency in Clojure, but I still want to understand this code.
(def *readers* (map #(agent %) '("one" "two" "three"))) (def *writers* (map #(agent %) '("four" "five"))) (def *mutex* (agent :unlocked)) (def *value* 0) ; mutex implementation (defn lock [state who success-fn fail-fn] (send who (if (= state :locked) fail-fn success-fn)) :locked) (defn unlock [mutex] :unlocked) ; Must be invoked with send-off since this handler blocks (defn rand-sleep [state next-fn] (Thread/sleep (rand-int 5)) (send *agent* next-fn) state) ; Reader functions (declare try-read) (defn reader-got-lock [name] (println (format "Thread %s says that the value is %d." name *value*)) (send *mutex* unlock) (send-off *agent* rand-sleep try-read) name) (defn reader-did-not-get-lock [name] (println (format "Thread %s tried to read the value, but could not." name)) (send-off *agent* rand-sleep try-read) name) (defn try-read [name] (send *mutex* lock *agent* reader-got-lock reader-did-not-get-lock) name) ; Writer functions (declare try-write) (defn writer-got-lock [name] (println (format "Thread %s is taking the lock." name)) (def *value* (rand-int 10)) (println (format "Thread %s is changing the value to %d." name *value*)) (send *mutex* unlock) (println (format "Thread %s is relasing the lock." name)) (send-off *agent* rand-sleep try-write) name) (defn writer-did-not-get-lock [name] (println (format "Thread %s tried to write the value, but could not." name)) (send-off *agent* rand-sleep try-write) name) (defn try-write [name] (send *mutex* lock *agent* writer-got-lock writer-did-not-get-lock) name) (dorun (map #(send % try-write) *writers*)) (dorun (map #(send % try-read) *readers*))
In particular, I am stuck on this line:
(defn try-write [name] (send *mutex* lock *agent* writer-got-lock writer-did-not-get-lock) name)
It must lock the mutexes and call either write-write-write, or write-write-not-get-lock, depending on the state of the mutexes. But where is *agent* declared, or is it a shortcut to access the current agent? Then, as state is passed to the lock, is it *agent* in the case of the above call, or *agent* is equal to who ?
source share