Concurrency 如何阻止线程直到条件变为真?
在Clojure中,如何阻止线程(未来),直到条件变为真?或者,或者,在某个条件变为真实之前继续重试?当您有条件变量时,这很容易,但我不确定Clojure的方法是什么 更具体地说,我有一个共享变量,可以被许多期货同时访问。未来应做到以下几点:Concurrency 如何阻止线程直到条件变为真?,concurrency,clojure,Concurrency,Clojure,在Clojure中,如何阻止线程(未来),直到条件变为真?或者,或者,在某个条件变为真实之前继续重试?当您有条件变量时,这很容易,但我不确定Clojure的方法是什么 更具体地说,我有一个共享变量,可以被许多期货同时访问。未来应做到以下几点: 检查变量的状态 如果状态满足某个条件,请将其更新为新状态 如果状态不满足该条件,则将来应该阻塞或重试,直到满足该条件(由另一个线程修改状态) Java平台支持条件变量,有关详细信息,请参阅文档 上述页面中的示例很容易翻译成Clojure: ;;; base
Java平台支持条件变量,有关详细信息,请参阅文档 上述页面中的示例很容易翻译成Clojure:
;;; based on the example in java.util.concurrent.locks.Condition
;;; documentation for JDK 1.7, see the link above
(defprotocol PBoundedBuffer
(-put [buf x])
(-take [buf]))
(import (java.util.concurrent.locks ReentrantLock Condition))
(deftype BoundedBuffer [^ReentrantLock lock
^Condition not-full?
^Condition not-empty?
^objects items
^:unsynchronized-mutable ^int putptr
^:unsynchronized-mutable ^int takeptr
^:unsynchronized-mutable ^int cnt]
PBoundedBuffer
(-put [buf x]
(.lock lock)
(try
(while (== cnt (alength items))
(.await not-full?))
(aset items putptr x)
(set! putptr (unchecked-inc-int putptr))
(if (== putptr (alength items))
(set! putptr (int 0)))
(set! cnt (unchecked-inc-int cnt))
(.signal not-empty?)
(finally
(.unlock lock))))
(-take [buf]
(.lock lock)
(try
(while (zero? cnt)
(.await not-empty?))
(let [x (aget items takeptr)]
(set! takeptr (unchecked-inc-int takeptr))
(if (== takeptr (alength items))
(set! takeptr (int 0)))
(set! cnt (unchecked-dec-int cnt))
(.signal not-full?)
x)
(finally
(.unlock lock)))))
(defn bounded-buffer [capacity]
(let [lock (java.util.concurrent.locks.ReentrantLock.)]
(BoundedBuffer. lock
(.newCondition lock)
(.newCondition lock)
(object-array capacity)
0
0
0)))
在REPL进行试驾:
(def bb (bounded-buffer 3))
(-put bb 1)
(-put bb 2)
(-put bb 3)
(future (-put bb 4) (println :foo))
(-take bb)
根据需要,在最后调用
-take
Clojure后,future会阻塞,然后打印:foo
,对于这类问题,如果您的问题没有任何副作用,听起来您可以使用refs。您可以在代理中存储正在检查的条件或值,并添加一块手表,一旦条件变为true
或该值为您想要的值,它将执行所需的操作:
(def x (agent 0))
(defn do-this-once-x-is-10 [key agnt old-val new-val]
(when (= new-val 10)
(println "x is now 10")))
(add-watch x :print-alert do-this-once-x-is-10)
(dotimes [_ 10]
(Thread/sleep 1000)
(send x inc))
; the value stored in x is incremented every second; after 10 seconds,
; the value of x will equal 10 and "x is now 10" will print
我碰巧看到了#clojure日志,似乎您实际上对这样一种场景感兴趣:共享资源由使用它的线程独占,然后返回到“可用”状态,以便在当前线程不再需要它时下一个线程拾取。您可以通过core.async使用一个缓冲区大小为1的通道来实现这一点:(1)创建通道--(chan 1)
,将其放在适当的位置--并将资源放在通道上;(2) 使用(请求对资源的独占保留(阻塞);(3)完成后,使用>返回资源!!
。