Concurrency 如何阻止线程直到条件变为真?

Concurrency 如何阻止线程直到条件变为真?,concurrency,clojure,Concurrency,Clojure,在Clojure中,如何阻止线程(未来),直到条件变为真?或者,或者,在某个条件变为真实之前继续重试?当您有条件变量时,这很容易,但我不确定Clojure的方法是什么 更具体地说,我有一个共享变量,可以被许多期货同时访问。未来应做到以下几点: 检查变量的状态 如果状态满足某个条件,请将其更新为新状态 如果状态不满足该条件,则将来应该阻塞或重试,直到满足该条件(由另一个线程修改状态) Java平台支持条件变量,有关详细信息,请参阅文档 上述页面中的示例很容易翻译成Clojure: ;;; base

在Clojure中,如何阻止线程(未来),直到条件变为真?或者,或者,在某个条件变为真实之前继续重试?当您有条件变量时,这很容易,但我不确定Clojure的方法是什么

更具体地说,我有一个共享变量,可以被许多期货同时访问。未来应做到以下几点:

  • 检查变量的状态
  • 如果状态满足某个条件,请将其更新为新状态
  • 如果状态不满足该条件,则将来应该阻塞或重试,直到满足该条件(由另一个线程修改状态)

  • 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)完成后,使用
    >返回资源!!