Ah, I see! Thank you very much. Yes, it would be helpful to get some more clarity on the transaction-long readlocking of ensure.
On 3/15/10, ataggart <alex.tagg...@gmail.com> wrote: > 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 > -- 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