Thanks for your post, Peter. I'm tracing the code, and it's interesting. The interesting point is definitely the agent's aq member, the AtomicReference that wraps an ActionQueue.
The aq.compareAndSet call keeps the value of the ActionQueue from switching out form under us while we attempt to set aq to a new ActionQueue wrapping a PersistentQueue that contains the agent's action -- the compareAndSet will be retried if it returns false. As I read the end of Agent's enqueue method, the action is only told to execute if the ActionQueue's PersistentQueue was empty before the compareAndSet and the ActionQueue is free of errors. I also see where Agent's static doRun method will pop an action off the agent's queue and execute the action. Where is Action's execute method called in the event the queue is not empty? Michael On May 26, 4:28 pm, Peter Schuller <peter.schul...@infidyne.com> wrote: > >> Unless I am misunderstanding the context in which the code runs, I > > > Which I was. Please ignore my previous post (sorry, think before I > > post... think before I post...) and consider me joined in the OP's > > question. > > And every time this happens I wonder if I should just leave it to > avoid flooding with responses further, or follow-up yet again, risking > the realization that I have to take something back *again*. > > I think I was confused the second time and right the first. But to > elaborate on my first post to clarify: > > As far as I can tell, execute() is only ever called by enqueue() and > enqueue() will only ever call execute() if the queue was non-empty > when the action was enqueued using the compareAndSet(). Further, if it > *was* empty, it always calls execute(). > > doRun() itself does a similar compareAndSet() loop and *always* > executes itself if the queue is non-empty. > > The resulting behavior is that any CAS loop that ends with the > realization that there was something already there to execute, leads > to said action being executed if needed. In the case of doRun() this > is accomplished by calling execute() itself - since doRun() is the one > already being executed, it knows it is done and that scheduling one > more action will lead not lead to a >1 concurrency level. In the case > of enqueue(), it either does nothing (if there was *already* something > there), or schedules the execution if the enqueue() invocation was > responsible for making the queue non-empty. > > In either case, the concurrency level can never go above 1. > > (I find this to be a very interesting use-case for immutable data > structures btw... it allows a complex data structure, without them in > and of themselves doing careful lock-less operations to support > concurrency, to be used in combination with simple CAS loops to great > effect.) > > -- > / Peter Schuller -- 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