I read at clojure.org/refs that
All reads of Refs will see a consistent snapshot of the 'Ref world' as of the starting point of the transaction (its 'read point'). The transaction will see any changes it has made. This is called the in-transaction-value.
There's also a link to Snapshot Isolation on wikipedia that implies that reads of any number of refs will be consistent with each other once a transaction has started.
I made a test case...
(def r1 (ref 0))
(def r2 (ref 0))
(defn delay-then-inc-ref [id ref delay]
(.start
(Thread.
#((println id " start")
(Thread/sleep delay)
(dosync
(alter ref inc))
(println id " end")))))
(defn deref-delay-deref [ref1 ref2 delay]
(.start
(Thread.
#((println "S start")
(dosync
(let [a @ref2]
(Thread/sleep delay)
(println "S r1=" @ref1))) ; @ref1 consistent with @ref2 ?
(println "S end")))))
*clojure-version*
;=> {:major 1, :minor 3, :incremental 0, :qualifier nil}
(deref-delay-deref r1 r2 2000)
(delay-then-inc-ref "1" r1 500)
(delay-then-inc-ref "2" r1 1000)
(delay-then-inc-ref "3" r1 1500)
The output is:
S start
1 start
2 start
3 start
1 end
2 end
3 end
r1 = 3
S end
nil
The value of r1 = 3
rather than r1 = 0
suggests that in deref-delay-deref
the deref of ref1 after the sleep
is picking the value of r1 after the three delay-then-inc-ref
transactions have occurred.
Note that I know about ensure
to prevent updates to refs by other transactions during a particular transaction, but I don't believe that applies here. I don't care if ref1
changes as long as I see a value consistent with the start of my transaction.
How does this behaviour fit with the above referenced documentation?