shakedzy
shakedzy

Reputation: 2893

Clojure: block the use of an atom?

I have a Clojure code which runs a few threads in parallel. They all share an atom: (def counter (atom 0)) which is incremented by each thread. Every 10 minute, I'd like to perform several actions using the value of the atom and then reset it back to 0 - for example:

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

It is important that the value of counter will not change from the moment it is dereferenced to the moment it is reset - meaning all threads should be blocked when trying to change the atom's value while publish-val is executed. How do I do this?

Upvotes: 1

Views: 381

Answers (2)

DaoWen
DaoWen

Reputation: 33029

Unless you've greatly simplified the problem for your example, it looks like swap!-ing out the current counter value with zero would be sufficient here:

(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 you just save your old counter value in a local variable, atomically swap it with zero, and then do whatever bookkeeping needed to do with the old value—all without stalling any of the other threads longer than it takes to swap!

Upvotes: 4

Stephen Greene
Stephen Greene

Reputation: 69

Use an agent.

See the section Using agents to serialise access to non-threadsafe resources about using them to print to console

Upvotes: 2

Related Questions