2017-03-06 40 views
0

我有一个并行运行几个线程的Clojure代码。它们都共享一个原子:(def counter (atom 0)),它由每个线程递增。每10分钟后,我想执行使用原子值几个动作,然后重置回0 - 例如:Clojure:阻止使用原子?

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

说的counter值将不会从此刻改变是很重要的它被解除引用到它被重置的那一刻 - 这意味着在尝试更改原子值时所有线程都应该被阻塞,而执行publish-val。我该怎么做呢?

回答

3

除非你已经大大简化了你的榜样的问题,它看起来像swap! -ing出与零电流计数器的值就足够了这里:

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

所以,你只需保存你的旧计数器值在一个局部变量,零原子交换,然后做旧做任何簿记需要的价值都没有拖延任何其他线程长的比它采取到swap!

+0

我觉得'(with-local-vars [c nil](重置!计数器(do(var-set c @counter)0))(println @c))'在这里更准确..你有什么理由喜欢'swap!'和'fn [c]'? – shakedzy

+1

@shakedzy - 使用'swap!'保证原子性。如果您使用'reset!',您可能会在读'@ counter'和调用'(reset!counter 0)''之间丢失'counter'的一些更新。 – DaoWen