简体   繁体   中英

Race condition with Clojure atom

I apparently do not understand clojure's atom correctly. I thought that it's atomicity guarantee could be demonstrated as follows:

(def users (atom #{}))

(defn add-user! [name]
  (swap! users
    (fn [users]
      (conj users name))))

(do
  (map deref
    [(future (add-user! "bob"))
     (future (add-user! "clair"))
     (future (add-user! "ralph"))
     (future (add-user! "mark"))
     (future (add-user! "bill"))
     (future (add-user! "george"))]))

(println @users)
(println
  (if (= 5 (count @users))
    "SUCCESS!"
    "FAIL"))

Unfortunately this is not the case. The code seems to exhibit a race condition on the set contained in the users atom.

Which data structure do I need to use to make sure that all users are successfully added to the users set?

SOLUTION

As pointed out in the comments, there were several bugs in the code. The main bug was not using dorun to force the evaluation of all of the futures. After making this change, the code runs as expected:

(def users (atom #{}))

(defn add-user! [name]
  (swap! users
    (fn [users]
      (conj users name))))

(dorun
  (map deref
    [(future (add-user! "bob"))
     (future (add-user! "clair"))
     (future (add-user! "ralph"))
     (future (add-user! "mark"))
     (future (add-user! "bill"))
     (future (add-user! "george"))]))

(println @users)
(println
  (if (= 6 (count @users))
    "SUCCESS!"
    "FAIL"))

See Clojure Atom documentation .

Also from Joy of Clojure:

Atoms are like Refs in that they're synchronous but are like Agents in that they're independent (uncoordinated).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM