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

Reply via email to