On Fri, Aug 14, 2009 at 8:53 PM, Mark Volkmann<r.mark.volkm...@gmail.com> wrote: > > On Fri, Aug 14, 2009 at 4:17 PM, Mark Volkmann<r.mark.volkm...@gmail.com> > wrote: >> On Thu, Aug 13, 2009 at 4:58 AM, Chas Emerick<cemer...@snowtide.com> wrote: >>> >>>> I know that if you have a dosync call in some function executed by a >>>> thread, and then that function calls other functions (which might have >>>> their own dosyncs, which get bundled together with the original >>>> transaction), then everything is fine. It seems common that all of >>>> that work would be done sequentially, in a single thread. >>>> >>>> But what if that thread that started the dosync did a pmap call, say, >>>> and the function called on each of the elements of the collection >>>> accessed Refs, and perhaps computed new values for some of them, and >>>> those were not the same Refs that the original thread was accessing. >>>> Do all of those get bundled together with the original transaction, >>>> too? >>> >>> Andy, >>> >>> No -- absent some var/binding gymnastics (which are currently possible >>> but not very straightforward to do at the moment) -- a transaction is >>> associated with a single thread, period. >>> >>> If your pmap call happens to initialize other transactions on other >>> threads, those transactions will be completed completely independently >>> of any transaction that may be in flight that initiated the pmap call >>> itself (or send or send-off or future, or whatever other asynchronous >>> mechanism at play). >>> >>> That said, I would urge caution in circumstances like what you've >>> described. While you say that the refs being accessed in the other >>> threads' transactions aren't the same as the refs being accessed in >>> the parent transaction, you'll be in for some unpleasantness if that >>> ceases to be true at some point. e.g. the "child" transactions will >>> see the original value of any refs changed so far in the "parent" >>> transaction, the parent will not see any changes made to those refs by >>> the child transactions, and if a parent transaction is waiting on a >>> value being returned by a child transaction, and they both ensure or >>> ref-set or alter the same ref, then you're likely in for a deadlock. >> >> Above you say "if ... they both ensure or ref-set or alter the same >> ref". I don't believe that can happen. Once one thread is successful >> in doing an ensure, ref-set or alter to a given Ref, that Ref is >> marked as having gotten a new in-transaction value in that transaction >> (the tinfo field of the Ref object gets set). This happens before the >> transaction commits. If another thread tries to do the same then >> either it or the original transaction is going to retry. I don't >> believe there is a possibility for deadlock here. >> >> Hold on! There was a recent change in LockingTransaction.java that may >> have made what I said above not exactly true! The LockingTransaction >> lock method is what sets the tinfo field of a Ref. Previously the lock >> method was called for an ensure, ref-set or alter. In the new version >> it seems that lock is only called for ref-set and alter. Can someone >> in the know confirm that this is the intended behavior? It seems that >> with this change it is now possible for more than one thread to ensure >> the same Ref as long as no thread has yet done a ref-set or alter on >> the Ref. > > I just studied this further. Before the recent changes to > LockingTransaction.java, only one thread at a time could ensure a > given Ref. With the changes, any number of threads can ensure the same > Ref. > > A key thing to know about this is that Ref.java uses a > ReentrantReadWriteLock. Each Ref has an associated > ReentrantReadWriteLock object. Those allow any number of threads to > simultaneously hold a read lock OR a single thread to hold a write > lock. > > All the threads that have called ensure on the Ref hold a read lock > for it. If one of them later tries to write to the Ref (by calling > ref-set or alter on it), it will release the read lock it holds for > the Ref and attempt to get a write lock for it. If other threads still > hold that read lock, this attempt will fail and the transaction will > retry. > > So it seems the biggest impact of the change can be summarized as > follows. In the past, once you successfully ensured a Ref, you knew > you could write to it later because no other thread could also ensure > it. Now you don't know that. You know you can stop other threads from > writing the Ref, but you won't be able to write the Ref as long as > other threads have also ensured it. > > I'm not criticizing the change. There were likely good reasons for it. > > Please let me know if I have interpreted anything incorrectly. >
While I appreciate that you are trying to understand the implementation of the STM, understanding the semantics of the STM in terms of its implementation is wrong-way-around. The semantics are simpler, and the implementation is subject to change. Retries will occur as needed to ensure the semantics, and no one should be thinking in terms of "if I do this and another transaction does that..." or read and write locks etc. Rich --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---