You'd need to use locking in both places since it's holding the monitor of the Ref instance, not the read/write locks, e.g.: (future (loop [] (Thread/sleep 500) (locking r (dosync (alter r inc))) (recur))) (locking r (dosync (alter r f)))
The point of ensure, as I see it, is to say only that the value will be consistent *when the commit occurs*. As for the whether the immediate read-lock-grabbing behavior of ensure should be replied upon, I can't say, though I'm inclined to no more rely on that than I am on the barging logic. Rich's input would be valuable here. On Mar 15, 3:24 pm, Garth Sheldon-Coulson <g...@mit.edu> wrote: > I would be happy to use locking if it's the more appropriate > construct. I tried it before ensure, in fact, because it seemed more > intuitive. > > ataggart, could you take a look at my first message? The code I posted > using locking didn't work for some reason, and I imagine I was doing > something wrong. > > Christophe, thanks for the partial memoization tip. I think that would > work in many cases, but for my current use case I really need to put a > lock on the ref, because the function is very expensive and other > threads will be updating it with previously unseen values so quickly > that memoization can't help. Are you saying that the fact that ensure > works in my example isn't to be counted on? > > On 3/15/10, ataggart <alex.tagg...@gmail.com> wrote: > > > > > > > If using ensure solves the problem then something else is going on, > > because ensure doesn't lock a ref for the life of the transaction any > > more than ref-set does. As the doc for ensure notes, it allows for > > *more* concurrency than ref-set, not less. From clojure.org/refs: > > > "All changes made to Refs during a transaction (via ref-set, alter or > > commute) will appear to occur at a single point in the 'Ref world' > > timeline (its 'write point')." > > > Ensure simply adds (after a bit of status checking) the ref to the set > > of refs that need to be locked and examined when commit occurs. From > > clojure.lang.LockingTransaction.doEnsure(Ref): > > > void doEnsure(Ref ref){ > > if(!info.running()) > > throw retryex; > > if(ensures.contains(ref)) > > return; > > ref.lock.readLock().lock(); > > > //someone completed a write after our snapshot > > if(ref.tvals != null && ref.tvals.point > readPoint) { > > ref.lock.readLock().unlock(); > > throw retryex; > > } > > > Info refinfo = ref.tinfo; > > > //writer exists > > if(refinfo != null && refinfo.running()) > > { > > ref.lock.readLock().unlock(); > > > if(refinfo != info) //not us, ensure is doomed > > { > > blockAndBail(refinfo); > > } > > } > > else > > ensures.add(ref); > > } > > > As for different constructs, they exist, one is 'ensure, the other is > > 'locking. > > > On Mar 15, 2:58 pm, Garth Sheldon-Coulson <g...@mit.edu> wrote: > >> Well it definitely seems that ensure has the behavior Michal > >> described, because the ensure code I posted works. I'm glad this > >> behavior is available, because I don't think there is any other way to > >> achieve the combination of synchronization and locking I need. (I > >> couldn't get locking to work on a ref; see my original msg.) > > >> Maybe the two different behaviors call for different constructs: one > >> for making sure an unmodified ref hasn't changed at commit time (the > >> original purpose I thought ensure was supposed to serve), and one with > >> the behavior I need here, namely causing all other modifications to > >> block for the remaining life of the transaction. > > >> On 3/15/10, ataggart <alex.tagg...@gmail.com> wrote: > > >> > On Mar 15, 1:43 pm, Michał Marczyk <michal.marc...@gmail.com> wrote: > >> >> On 15 March 2010 21:08, Meikel Brandmeyer <m...@kotka.de> wrote: > > >> >> > Now I'm confused. Calling ensure on r shouldn't have an effect since > >> >> > we > >> >> > call alter on r anyway, no? > > >> >> ensure "protects the ref from modification by other transactions" > >> >> (from the docs). alter does not. > > >> >> Reading into the Java code, ensure puts a lock on the ref, which, once > >> >> in place, guarantees that the transaction doing the ensuring has an > >> >> exclusive right to modify the ref until it commits / retries... or > >> >> something, my Java-fu is still nothing to boast about, regrettably. > > >> >> At any rate, my current understanding is that, in Garth's example, the > >> >> ensure gives (alter r f) all the time it needs to modify r's value > >> >> while putting all other transactions which attempt to modify r on > >> >> hold. alter, by itself, never interferes with background transactions; > >> >> should something disappear from under its feet, it expects to be > >> >> retried. > > >> >> Ok, back to improving my Java chops in the hope of grasping all the > >> >> intricasies of Rich's code sometime... *sigh* > > >> >> Sincerely, > >> >> Michał > > >> > I'm inclined to say this is incorrect as I'm on my iphone so I can't > >> > look at the source. The concurrency functions (e.g., ref-set, alter, > >> > ensure) only lock their refs during the commit process. The ensure > >> > function is provided to add a *non-changing* ref to the set of refs > >> > that need to be locked; ref-set, etc., do this implicitly. To lock > >> > the refs upon first use would largely obviate the point of the STM. > > >> > The issue Garth describes is a case of live-locking, an extant failure > >> > mode of the STM. Some solutions would be to break up the work from > >> > just a single transaction (though sacrificing consistency), or use the > >> > locking construct: > >> >http://richhickey.github.com/clojure/clojure.core-api.html#clojure.co... > > >> > -- > >> > 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 > > >> -- > >> Sent from my mobile device > > > -- > > 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 > > -- > Sent from my mobile device -- 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