Hi, disclaimer: I'm completely incompetent in terms of the STM. The following is my understanding what happens. It might be completely wrong. Ignore at will.
On Mar 2, 2:40 am, "Steven E. Harris" <s...@panix.com> wrote: > (dosync > (or (*id-node-map* id) > (alter *id-node-map* > #(assoc % id (create-default))))) > > Ignoring the defect that each branch of the `or' form returns a > different kind of value (in one case, the mapped value, in the other > case, the map itself), I wondered whether it's possible that in between > when I first lookup the value and find it missing and when `alter' runs > that another thread could have jammed a value in there. I think this is what's the STM is all about: coordinating changes. A: lookup fails--------adds default via alter-----commit--- B: -------lookup fails--------adds default via alter------commit So A changes the map under the fingers of B. But the STM will notice the conflict at commit time of B and retries. On the second run the lookup succeeds and the value is returned. So using alter is the absolutely correct and nothing bad will happen. However you might construct superfluous default nodes in case the action is retried. They are not assoc'd to the map, though. Sidenote: you can write (dosync (or (*id-node-map* id) (let [n (default-node)] (alter *id-node-map* assoc id n) n)) The anonymous function is not necessary. > o What happens if two threads run this operation concurrently? Will one > fail and retry, backing off for finding the value now present in the > map? This is my expectation. What leads you to the idea it would be different? I think this is the whole point about STM, that you don't have to worry about such things. > o Is there some map updating operation better suited to my goal here? > The lookup ahead of time seems like it might not be necessary. There is (get the-map id (default-node)), but this does not assoc the value to the map. I assume your (default-node) is a little more complicated - and in particular non-constant. > o Is there some way to capture the new value associated with the key > without looking it up again /outside/ and /after/ the `dosync' form? > The contract is that there's either no value associated with the key > or there is a value, and once there's a value it will not change to be > a different value. (These values are themselves agents.) But it's hard > to tell from within `dosync' whether a proposed update to the map will > be the one than wins. I think the let above solves this problem, no? > o Assuming that `alter' is germane to the solution, how would `commute' > behave differently? I understand that `commute' doesn't block writers > and hence can retry. In my case, retrying after losing in the > collision should result in finding that the competing thread already > bound a value to the given key in the map. In contrast to alter, commute would in case of conflict just go on and assoc the id again. This is not a problem if the nodes are values. But as you said: agents are not values. So you would overwrite the first agent and your application would be broken by race condition, because there might be a short time where outside observer would see the first agent. I think alter is exactly the right tool. Sincerely Meikel -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en