2014-04-16 4 views
3

Clojure에서 조건이 true가 될 때까지 스레드 (미래)를 어떻게 차단합니까? 또는, 조건이 사실이 될 때까지 계속 재 시도하십시오. 조건 변수가있을 때 이것은 쉽지만, Clojure 방법은 무엇인지 잘 모르겠습니다.조건이 참이 될 때까지 스레드를 어떻게 차단합니까?

더 구체적으로 말하자면, 많은 미래에 동시에 액세스 할 수있는 공유 변수가 있습니다. 미래는 다음을 수행해야합니다.

  1. 변수의 상태를 확인하십시오.
  2. 상태가 특정 조건을 충족하면 새 상태로 업데이트하십시오.
  3. 상태가 조건을 충족하지 못하면 미래는 조건이 충족 될 때까지 (상태를 수정하는 다른 스레드가) 차단하거나 다시 시도해야합니다.
+3

무슨 일이 있었을 #clojure 로그를 살펴보면 실제로 공유 리소스가 공유 리소스를 사용하는 스레드에 의해 독점적으로 보관 된 다음 다음 스레드가 한 번 픽업 할 수 있도록 "사용 가능"상태로 돌아가는 시나리오에 관심이있는 것으로 보입니다 현재 스레드가 더 이상 필요하지 않습니다. 크기가 1 인 버퍼를 가진 채널을 사용하여 core.async로 할 수 있습니다 : (1) 채널을 생성합니다 -'(chan 1)', 적절한 곳에 넣고 채널에 자원을 넣으십시오; (2)'( !! '와 함께 반환하십시오. –

답변

1

Java 플랫폼은 조건 변수를 지원합니다. java.util.concurrent.locks.Condition에 대한 설명서를 참조하십시오.

상기 페이지에서 예 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) 

가 미래 블록 후 최종 호출 후 :foo를 인쇄 -take.

0

Clojure는 이러한 종류의 문제로 refs, agentsatoms을 제공하며 문제에 부작용이 없다면 refs를 사용할 수있는 것처럼 들립니다.

당신은 에이전트에서 확인하고있는 상태 또는 값을 저장하고, 조건이 true이되거나 값이 원하는 값되면 원하는 작업을 수행 시계 추가 할 수
0

:

(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 
관련 문제