Ord
Ord

Reputation: 5843

What are the semantics of a clojure ref-set that doesn't "read" the ref?

I've read this SO question and http://clojure.org/refs, but I am still confused about how exactly ref-set works. (To some extent the two documents kind of lead me to believe two different things...)

Suppose that I have a transaction in Clojure that looks like this:

(def flag (ref false))
(dosync
    (long-computation-that-does-not-read-or-write-flag)
    (ref-set flag true))

Suppose that in the middle of the long computation, somebody else modifies flag. Will that cause my transaction to retry when I try to ref-set flag?

I could imagine the answer might be yes, since clojure.org says transactions guarantee that "No changes will have been made by any other transactions to any Refs that have been ref-set/altered/ensured by this transaction".

But I could also imagine the answer to be no, since I never read flag, and the clojure.org page suggests that "All *reads* of Refs will see a consistent snapshot of the 'Ref world' as of the starting point of the transaction". This is also what the linked SO answer would lead me to believe.

And a followup: supposing that instead of (ref-set flag true), I had done one of these:

  1. (alter flag (fn [_] true))
  2. (let [ignored @flag] (ref-set flag true))

I assume that both of those would constitute a read of flag, and so the transaction would have to retry?

Upvotes: 3

Views: 190

Answers (1)

Alex Miller
Alex Miller

Reputation: 70211

Calling ref-set means that you have included flag in the tracked references for this transaction. Thus, a concurrent write to flag in some other transaction will cause a conflict and a retry.

Both of the followups modify flag (via alter and ref-set) and thus have the same result. The important thing here is not the read of flag, it's the write. If a transaction contains a read of a ref without a write, the transaction can succeed even if the read ref changes in a concurrent transaction. However, ensure can be used to include a read in the tracked references for a transaction (thus causing concurrent changes to fail).

Upvotes: 3

Related Questions