Transactions in Clojure are "optimistic": the runtime assumes that everything will work out, and if not, it retries.
Basically, when a transaction starts, the runtime makes a copy of the current value of all refs involved in the transaction (these are assumed to be immutable values, so copies are cheap). It then executes the transaction in an isolated context, i.e. it runs the code of the dosync based only on the values it has cached, with no regard for potentially concurrent transactions at all. When the code in the dosync is finished, the result is a set of new values for the involved refs. At that point, the runtime "stops the world" (prevents write access to exactly these refs) and compares the current values of the refs with the values it had saved at the beginning of the dosync. If they are the same, the system now stops the world even more (prevents reading from these refs) and updates all of the involved refs. Once all the new values are written and properly published, the protection is lifted and other threads trying to read or write these refs (if there are any) are unblocked. If the old values are not equal to the current values, the system discards the new values, stores de current values in place of the old values for this thread, lifts the protection on the refs, and runs all of the dosync code again. This is a basic mental model that is going to be mostly accurate from a user point of view. The real system is more complex and involves support for commutative operations (just rerun the code to update this one ref instead of all of the transaction if only this ref has changed) and some support for priority management - it is easy to imagine, with the structure painted above, a situation in which a stream of fast transactions force a slow transaction to restart indefinitely. I think I remember reading somewhere that the system made some attempt at preventing that. Disclaimer: I've never needed refs, so all of my knowledge comes from dimly remembered readings when I was first learning Clojure three years ago. Someone please correct me if the above is not correct. On Monday, 27 October 2014, Øyvind Teig <oyvind.t...@gmail.com> wrote: > Gary, thank you! > > kl. 22:41:02 UTC+1 søndag 26. oktober 2014 skrev Gary Verhaegen følgende: >> >> Transactions themselves are not queued (besides the obvious queueing >> of threads when you have more threads than cores). What gets >> adaptively queued is the historical values of refs involved in >> transactions. >> >> So if you have three concurrent transactions running, and three refs >> are involved in two of these transactions, and a fourth refs in >> involved in all three, the system will probably need to keep two >> previous values for the first three refs and three previous values for >> the last ref. >> > > Interesting. In my "Atomic for all?" blog ( > http://www.teigfam.net/oyvind/home/technology/090-atomic-for-all/ (*)) I > wrote about some implementation details of atomic, where I quoted a guy I > had talked with at a conference: "For some atomic implementations the > hardware needs four copies of the atomic variable, and there are four > booleans – three written by the writer and one by the reader.". Would the > ideas behind the clojure transactions be along that line, or am I shooting > too far out: Make a table of the possibilities of getting something wrong > then store what you need to be able to get things in order? (I do have a > thick book about transactions, a friend said I needed it, but it's too > thick for one life! But I know what might happen when I book a flight; it > happened today! I came home, but 4 h late and one leg too much!) > > (*) My blog, no ads, no money involved, just curriculum. > >> >> Code within a transaction should not have any other visible effect >> than updating refs. When a transaction reaches its end, the system >> checks the (current) value of all involved refs and retries if any has >> changed. >> >> On 26 October 2014 21:03, Leon Grapenthin <grapent...@gmail.com> wrote: >> > >> > >> > On Sunday, October 26, 2014 11:37:43 AM UTC+1, Øyvind Teig wrote: >> >> >> >> I have been reading myself up on Clojure concurrency, starting at [1]. >> In >> >> [2] I read that >> >> >> >>> The Clojure STM uses multiversion concurrency control with adaptive >> >>> history queues for snapshot isolation, and provides a distinct >> commute >> >>> operation >> >> >> >> >> >> but it still needs some explanation to me. Software transactional >> memory >> >> (STM) is described ok. >> >> >> >> But the "adaptive history queues" looks like implementation. In ADA, >> tasks >> >> on rendezvous queue up (so the Ravenscar high security profile >> prohibits >> >> them because they are non-deterministic). In Go goroutines on >> selective >> >> choice's select are queued (also nondeterministic). In occam the there >> is no >> >> such queue on the ALT. How is the Clojure queue, and what does it >> contain? >> >> >> >> I see that exchanging data between Clojure concurrent functions >> (threads?) >> >> described. But I haven't discovered how a "thread" that succeeds in >> writing, >> >> followed by a successful write immediately after by another thread - >> is >> >> "signalled" to the first thread? Is there any wait type of mechanism? >> > >> > >> > There is no signalling. The "write" in the first thread always succeeds >> > within the transaction but the "real world" is not affected until the >> > transaction succeeds as a whole. If during the transaction another >> > transaction succeeded, it is retried as a whole, potentially with the >> new >> > values written by the other transaction, until it has also succeeded. >> > >> >> >> >> >> >> If a write fails and there is a retry, what's the limit of retries, is >> >> there a yield in between, and in case, how is this entry queued? >> > >> > >> > There is no limit. (Unfortunately I don't know about the implementation >> > details and hopefully somebody else can enlighten you on that.) >> > >> >> >> >> >> >> Is it correct to say that never to block means never to be 100% sure >> that >> >> a transaction succeeds at first attempt? >> > >> > Yes. >> >> >> >> >> >> [3] states on commute that "Thus fun should be commutative, or, >> failing >> >> that, you must accept last-one-in-wins behavior. commute allows for >> more >> >> concurrency than ref-set.". What's the metric of concurrency? No, >> little, >> >> some, more, much, max? >> > >> > >> > How much happens at the same time in contrast to being queued up. >> Remember >> > that only successful transactions affect the outside world. E. g.: Of >> two >> > successful transactions, one had to be restarted because of the other >> > completed during its first try => The two successful transactions >> didn't >> > happen in parallel. Using commute reduces the potential of a retry and >> thus >> > allow more successful transactions in parallel => more concurrency. >> > >> >> >> >> >> >> I would have more questions, but they will come. >> >> >> >> I plan to blog about these matters at [4]. It's a do-for-fun only >> blog, >> >> with no money or ads involved. I try to read myself up via atomic to >> several >> >> other concurrency models than CSP, which is flowing in my veins the >> last 25 >> >> years. >> >> >> >> Øyvind Teig, Trondheim, Norway >> >> >> >> [1] - http://clojure.org/concurrent_programming >> >> [2] - http://clojure.org/Refs >> >> [3] - >> >> http://clojure.github.io/clojure/clojure.core-api.html# >> clojure.core/commute >> >> [4] - http://www.teigfam.net/oyvind/home/technology/ >> > >> > -- >> > You received this message because you are subscribed to the Google >> > Groups "Clojure" group. >> > To post to this group, send email to clo...@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+u...@googlegroups.com >> > For more options, visit this group at >> > http://groups.google.com/group/clojure?hl=en >> > --- >> > You received this message because you are subscribed to the Google >> Groups >> > "Clojure" group. >> > To unsubscribe from this group and stop receiving emails from it, send >> an >> > email to clojure+u...@googlegroups.com. >> > For more options, visit https://groups.google.com/d/optout. >> > -- > 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 > <javascript:_e(%7B%7D,'cvml','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 > <javascript:_e(%7B%7D,'cvml','clojure%2bunsubscr...@googlegroups.com');> > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en > --- > You received this message because you are subscribed to the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to clojure+unsubscr...@googlegroups.com > <javascript:_e(%7B%7D,'cvml','clojure%2bunsubscr...@googlegroups.com');>. > For more options, visit https://groups.google.com/d/optout. > -- 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 --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.