2017-03-06 5 views
0

Ich habe einen Clojure-Code, der ein paar Threads parallel läuft. Sie teilen sich alle ein Atom: (def counter (atom 0)), das von jedem Thread inkrementiert wird. Jede 10 Minuten, würde Ich mag verschiedene Aktionen mit dem Wert des Atoms führen und es dann auf 0 zurückgesetzt - zum Beispiel:Clojure: Blockieren Sie die Verwendung eines Atoms?

(defn publish-val [] 
    (let [c @counter] 
    (email c) 
    (statsd c) 
    (print-log c) 
    (reset! counter 0))) 

Es ist wichtig, dass der Wert von counter nicht von dem Moment ändern Es ist dereferenziert auf den Moment, wenn es zurückgesetzt wird - was bedeutet, dass alle Threads blockiert werden sollten, wenn versucht wird, den Wert des Atoms zu ändern, während publish-val ausgeführt wird. Wie mache ich das?

Antwort

3

zu trösten zu drucken, wenn Sie stark das Problem für Ihr Beispiel vereinfacht haben, sieht es aus wie swap! mit Null den aktuellen Zählerwert -ing würde hier ausreichend sein:

(defn publish-val [] 
    (with-local-vars [c nil] 
    (swap! counter 
      (fn [x] (var-set c x) 0)) 
     (email @c) 
     (statsd @c) 
     (print-log @c))) 

So sparen Sie nur Ihren alten Zählerwert in einer lokalen variablen, tauschen sie atomar mit Null, und dann tun, was Buchhaltung mit der alten zu tun, benötigen wert alles ohne länger keines der anderen Fäden Abwürgen als es dauert, zu swap!

+0

Ich denke '(mit-lokalen-vars [c nil] (Reset! counter (do (var-set c @ counter) 0)) (println @c)) 'ist genauer hier .. gibt es einen Grund, warum Sie' swap! 'und' fn [c] 'bevorzugten? – shakedzy

+1

@shakedzy - Die Verwendung von 'swap!' Garantiert die Atomarität. Wenn Sie stattdessen 'reset!' Verwenden, verlieren Sie möglicherweise einige Aktualisierungen zu 'counter' zwischen dem Lesen von' @ counter' und dem Aufruf von '(reset! Counter 0)'. – DaoWen

Verwandte Themen