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. -- R. Mark Volkmann Object Computing, Inc. --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---