Re: The code example in onSpinWait() Javadoc
Francesco Nigro via Concurrency-interest <[email protected]>
| Newsgroups | gmane.comp.java.jsr.166-concurrency |
|---|---|
| Message-ID | <CAKxGtTXPUmgPpOZOJsa+7i008gaM3wxRtuhnwW8-_-5wJyuR1g@mail.gmail.com> |
Agree on all your points, just hope you won't shudder too much of my inappropriate use of "time" word :) (with double quotes on purpose), but let me try to improve it: on my goofy attempt to show a better example, there was a properly established happens before relationship ensuring that the condition awaited on the spin wait loop would hold after a finite amount of iterations, in theory, but infinite in practice, due to OS scheduling decisions. Turning a possibly nice wait free algorithm into a lock-free one for the sake of making it faster in the common path is a frequent choice for many data-structures and using onSpinWait in similar scenarios really improve the worst case latency ie is a proper use case for it. I believe that *at least* providing some context to the user would be better, although I understand that is outside the scope of the doc to tech concurrent programming to the reader. Il ven 15 nov 2019, 00:11 Alex Otenko <[email protected]> ha scritto: > That's the thing, I don't see what is more complex or more instructive > about the differently written loop that breaks on observing a 1-bit state > change. > > When I hear "time" pronounced in the context of wait, I shudder. Strict > time bound makes no sense in a non real time OS. You can only formulate a > termination condition in terms of happens before. So you can only say "10ms > elapses before I will break out of the wait loop". But you don't need > onSpinWait to know that. In fact, you just can't implement it without a > computation model with arbitrary suspension points. > > Alex > > > On Thu, 14 Nov 2019, 22:22 Francesco Nigro, <[email protected]> wrote: > >> Beside being more complex? >> Not much I admit :) >> But IMO awaiting with no algorithmical indication of the duration of the >> wait (like in the javadoc) and awaiting for a finite amount of "time" a >> condition that will be true at some point, is a better example where to >> apply onSpinWait, although is not technically incorrect to use it for >> "blind" spin loop as well. >> Maybe is just a subtle difference, but I won't encourage users to blindly >> spin loop on conditions and just use onSpinWait to save the day.. probably >> I'm worried too much for something very simple and unavoidable; as @roman >> has suggested, probably no example is better then one that is a superclass >> of all the possible best cases. >> >> >> Il gio 14 nov 2019, 22:51 Alex Otenko <[email protected]> ha >> scritto: >> >>> What's the difference between this example and what's in javadocs? >>> >>> Alex >>> >>> On Thu, 14 Nov 2019, 16:29 Francesco Nigro via Concurrency-interest, < >>> [email protected]> wrote: >>> >>>> Totally right, sorry again (writing by phone is a terrible idea :( ): >>>> yes , poll should use "o = this.obj". >>>> >>>> > Can we get rid of "done"? Since offerOnce() does not allow null, >>>> then having the done flag does not seem to help anything. >>>> Absolutely yes: I've prepared this as a "simplified" (and wrong due to >>>> the hurry, sorry for that) version of what we do on many queues in JCtools, >>>> that's why it contains some unnecessary bits as you've rightly pointed >>>> out. >>>> Code that is spin awaiting on a condition, sure that it will happen at >>>> some point in the future, is something that could help to understand the >>>> rare cases >>>> where using onSpinWait could be beneficial IMO. >>>> >>>> >>>> >>>> Il giorno gio 14 nov 2019 alle ore 17:18 Nathan and Ila Reynolds < >>>> [email protected]> ha scritto: >>>> >>>>> In poll(), should "this.obj = o" be "o = this.obj"? Without this >>>>> change, it seems poll() could spin forever. >>>>> >>>>> Should "poll" be renamed to "take" since the method could block until >>>>> a value is available? >>>>> >>>>> Can we get rid of "done"? Since offerOnce() does not allow null, then >>>>> having the done flag does not seem to help anything. >>>>> >>>>> Is the compiler and execution engine in my head misinterpreting and >>>>> mis-executing the code? >>>>> >>>>> Here is the code with my suggested changes. >>>>> volatile E obj = null; >>>>> >>>>> public void offerOnce(E o) { >>>>> Objects.checkNonNull(o); >>>>> this.obj = o; >>>>> } >>>>> >>>>> public boolean isDone() { >>>>> return obj != null; >>>>> } >>>>> >>>>> public E take() { >>>>> E o; >>>>> >>>>> while (true) { >>>>> o = obj; >>>>> >>>>> if (o != null) >>>>> return o; >>>>> >>>>> java.lang.Thread.onSpinWait(); >>>>> } >>>>> } >>>>> >>>>> -Nathan >>>>> >>>>> On 11/14/2019 8:54 AM, Francesco Nigro wrote: >>>>> >>>>> Sorry I've written on the email text, I forgot an important part, let >>>>> me write it properly: >>>>> >>>>> volatile E obj = null; >>>>> volatile boolean done = false; >>>>> >>>>> public void offerOnce(E o) { >>>>> Objects.checkNonNull(o); >>>>> this.done = true; >>>>> this.obj = o; >>>>> } >>>>> >>>>> public boolean isDone() { >>>>> return done; >>>>> } >>>>> >>>>> public E poll() { >>>>> E o = this.obj; >>>>> if (o == null && !this.done) { >>>>> return null; >>>>> } >>>>> //o will be !null at some point >>>>> do { >>>>> if (o != null) >>>>> return o; >>>>> java.lang.Thread.onSpinWait(); >>>>> this.obj = o; >>>>> } while(true); >>>>> } >>>>> >>>>> Similarly to the queue API: poll should return null iff !done, but >>>>> offer update first done and then this.obj: >>>>> poll need to read obj, but has to stay consistent to the ordering, so >>>>> at some point, obj will be visible if done == true. >>>>> On JCtools we have some queues with a similar behaviour (producer >>>>> sequence is advanced before writing the actual element in the queue) >>>>> and we need to spin wait the element apprearence to stay consistent >>>>> with the isEmpty behaviour: that's a good use case for onSpinWait (when it >>>>> works :P). >>>>> >>>>> >>>>> >>>>> Il giorno gio 14 nov 2019 alle ore 16:43 Andrew Haley <[email protected]> >>>>> ha scritto: >>>>> >>>>>> On 11/14/19 3:31 PM, Francesco Nigro via Concurrency-interest wrote: >>>>>> > E o = this.obj; >>>>>> > if (o == null && !done) { >>>>>> > return null; >>>>>> > } >>>>>> > //o will be !null at some point >>>>>> > do { >>>>>> > if (o != null) >>>>>> > return o; >>>>>> > java.lang.Thread.onSpinWait(); >>>>>> > } while(true); >>>>>> > } >>>>>> > >>>>>> > In case like this is more appropriate, maybe, but much less >>>>>> intuitive >>>>>> > probably. >>>>>> >>>>>> Umm, what? o is a local. This loop spins forever. >>>>>> >>>>>> -- >>>>>> Andrew Haley (he/him) >>>>>> Java Platform Lead Engineer >>>>>> Red Hat UK Ltd. <https://www.redhat.com> >>>>>> https://keybase.io/andrewhaley >>>>>> EAC8 43EB D3EF DB98 CC77 2FAD A5CD 6035 332F A671 >>>>>> >>>>>> _______________________________________________ >>>> Concurrency-interest mailing list >>>> [email protected] >>>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest >>>> >>> _______________________________________________ Concurrency-interest mailing list [email protected] http://cs.oswego.edu/mailman/listinfo/concurrency-interest