I was wondering wether Clojure has a built in solution for the ABA-problem. I was creating an example that shows this problem, but somehow Clojure detects the changes. Is this because Clojure's transactions compare the references and not the values?
My example:
(def x (ref 42))
(def io (atom false))
(def tries (atom 0))
(def t1 (Thread. (fn [] (dosync (commute x - 42)))))
(def t2 (Thread. (fn [] (dosync
(Thread/sleep 100)
(commute x + 42)))))
(def t3 (Thread.
(fn []
(dosync
(do
(Thread/sleep 1000)
(swap! tries inc)
(if (= 42 @x)
(reset! io true)))))))
(.start t3)
(.start t1)
(.start t2)
(.join t1)
@x
(.join t2)
@x
(.join t3)
@tries
(if (= true @io) (println "The answer is " @x))
The tries count is always 2, so the transaction t3 must have noticed the ref changes of t1 and t2. Does someone know the cause of this behavior?
You are correct that this is the expected behavior (although I would have expected
triesto be 1). Besides the many Clojure books discussing Software Transactional Memory (STM), you may also wish to reviewAlso, it is usually best to use
alterinstead ofcommute, which is easy to get wrong and is usually a case of "premature optimization".