关于并发:了解此Clojure代码

Understanding this Clojure code

我对Clojure还是很陌生,我一直在努力实现一些并发代码。我在网上找到了此代码。有一个警告,它不是在Clojure中进行并发的正确方法,但是我还是想理解这段代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
(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*))

具体地说,我被困在这一行:

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

它应该锁定互斥锁,并根据互斥锁状态调用writer-got-lock或writer-did-not-get-lock。但是*agent*在哪里声明,还是访问当前代理的快捷方式?那么state如何传递给锁,在上述调用的情况下是*agent*还是whowho


*agent*是当前代理的快捷方式,由clojure隐式提供。 *agent*作为who传递。最终调用大致如下:

1
(lock @*mutex* *agent* writer-got-lock writer-did-not-get-lock)