4

I'm very new to Clojure and I've been struggling to implement some concurrent code. I've found this code on the web. There is a warning that it is not a proper way to do concurrency in Clojure, but I want to understand this code anyway.

(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*))

Specifically I'm stuck at this line:

(defn try-write [name]
  (send *mutex* lock *agent* writer-got-lock writer-did-not-get-lock)
  name)

It should lock the mutex and call either writer-got-lock or writer-did-not-get-lock depending on the mutexes state. But where is *agent* declared, or is it a shortcut to access the current agent? Then how a state is passed to the lock, is it *agent* in case of the above call or *agent* is who?

1 Answer 1

5

*agent* is a short-cut for the current agent and is implicitly provided by clojure. *agent* is passed as who. The final call roughly looks like this:

(lock @*mutex* *agent* writer-got-lock writer-did-not-get-lock)
Sign up to request clarification or add additional context in comments.

1 Comment

And what do such constructions as name at the end of try-write or :locked in lock mean? Does it set the caller agent to this state after executing the function?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.