The code example in onSpinWait() Javadoc

classic Classic list List threaded Threaded
34 messages Options
12
Reply | Threaded
Open this post in threaded view
|

The code example in onSpinWait() Javadoc

JSR166 Concurrency mailing list
Thread.onSpinWait()'s Javadoc has the following code example:

     class EventHandler {
         volatile boolean eventNotificationNotReceived;
         void waitForEventAndHandleIt() {
             while ( eventNotificationNotReceived ) {
                 java.lang.Thread.onSpinWait();
             }
             readAndProcessEvent();
         }

         void readAndProcessEvent() {
             // Read event from some source and process it
              . . .
         }
     }

Which doesn't seem to me as the best practice of using Thread.onSpinWait().

Thread.onSpinWait() is used in a very few classes in JDK itself, even compared to other low-level mechanisms such as LockSupport.park/unpark. It's hard to use it right. Cf. a recent thread "Low-latency pause in JDK" in this mailing list.

Maybe, in this case, it's better to not provide any usage example than to provide such half-baked/"context and caveats" example, to prevent users from copying this pattern from the highly visible Thread class's Javadocs?

Expert users, the target audience for this method, unlikely benefit from the present example either.

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: The code example in onSpinWait() Javadoc

JSR166 Concurrency mailing list
I suppose this begs the question for the community.  What would be the perfect example?

On Thu, Nov 14, 2019 at 7:48 AM Roman Leventov via Concurrency-interest <[hidden email]> wrote:
Thread.onSpinWait()'s Javadoc has the following code example:

     class EventHandler {
         volatile boolean eventNotificationNotReceived;
         void waitForEventAndHandleIt() {
             while ( eventNotificationNotReceived ) {
                 java.lang.Thread.onSpinWait();
             }
             readAndProcessEvent();
         }

         void readAndProcessEvent() {
             // Read event from some source and process it
              . . .
         }
     }

Which doesn't seem to me as the best practice of using Thread.onSpinWait().

Thread.onSpinWait() is used in a very few classes in JDK itself, even compared to other low-level mechanisms such as LockSupport.park/unpark. It's hard to use it right. Cf. a recent thread "Low-latency pause in JDK" in this mailing list.

Maybe, in this case, it's better to not provide any usage example than to provide such half-baked/"context and caveats" example, to prevent users from copying this pattern from the highly visible Thread class's Javadocs?

Expert users, the target audience for this method, unlikely benefit from the present example either.
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest


--
-Nathan

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: The code example in onSpinWait() Javadoc

JSR166 Concurrency mailing list
A trivial spin lock?

On Thu, Nov 14, 2019 at 9:18 AM Nathan and Ila Reynolds via
Concurrency-interest <[hidden email]> wrote:

>
> I suppose this begs the question for the community.  What would be the perfect example?
>
> On Thu, Nov 14, 2019 at 7:48 AM Roman Leventov via Concurrency-interest <[hidden email]> wrote:
>>
>> Thread.onSpinWait()'s Javadoc has the following code example:
>>
>>      class EventHandler {
>>          volatile boolean eventNotificationNotReceived;
>>          void waitForEventAndHandleIt() {
>>              while ( eventNotificationNotReceived ) {
>>                  java.lang.Thread.onSpinWait();
>>              }
>>              readAndProcessEvent();
>>          }
>>
>>          void readAndProcessEvent() {
>>              // Read event from some source and process it
>>               . . .
>>          }
>>      }
>>
>> Which doesn't seem to me as the best practice of using Thread.onSpinWait().
>>
>> Thread.onSpinWait() is used in a very few classes in JDK itself, even compared to other low-level mechanisms such as LockSupport.park/unpark. It's hard to use it right. Cf. a recent thread "Low-latency pause in JDK" in this mailing list.
>>
>> Maybe, in this case, it's better to not provide any usage example than to provide such half-baked/"context and caveats" example, to prevent users from copying this pattern from the highly visible Thread class's Javadocs?
>>
>> Expert users, the target audience for this method, unlikely benefit from the present example either.
>> _______________________________________________
>> Concurrency-interest mailing list
>> [hidden email]
>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>
>
>
> --
> -Nathan
> _______________________________________________
> Concurrency-interest mailing list
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest



--
- DML

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: The code example in onSpinWait() Javadoc

JSR166 Concurrency mailing list
In reply to this post by JSR166 Concurrency mailing list
I would expect it on ConcurrentLinkedQueue::poll spin loop, but cannot say if is "that better" :)
It doesn seem so weird to me, but  maybe:

given:

volatile E obj = null;
volatile boolean done = false;

publisher thread:

this.obj = //a valid non null value
this.done = true;

receiver thread:

E poll() {
    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.


Il giorno gio 14 nov 2019 alle ore 16:18 Nathan and Ila Reynolds via Concurrency-interest <[hidden email]> ha scritto:
I suppose this begs the question for the community.  What would be the perfect example?

On Thu, Nov 14, 2019 at 7:48 AM Roman Leventov via Concurrency-interest <[hidden email]> wrote:
Thread.onSpinWait()'s Javadoc has the following code example:

     class EventHandler {
         volatile boolean eventNotificationNotReceived;
         void waitForEventAndHandleIt() {
             while ( eventNotificationNotReceived ) {
                 java.lang.Thread.onSpinWait();
             }
             readAndProcessEvent();
         }

         void readAndProcessEvent() {
             // Read event from some source and process it
              . . .
         }
     }

Which doesn't seem to me as the best practice of using Thread.onSpinWait().

Thread.onSpinWait() is used in a very few classes in JDK itself, even compared to other low-level mechanisms such as LockSupport.park/unpark. It's hard to use it right. Cf. a recent thread "Low-latency pause in JDK" in this mailing list.

Maybe, in this case, it's better to not provide any usage example than to provide such half-baked/"context and caveats" example, to prevent users from copying this pattern from the highly visible Thread class's Javadocs?

Expert users, the target audience for this method, unlikely benefit from the present example either.
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest


--
-Nathan
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: The code example in onSpinWait() Javadoc

JSR166 Concurrency mailing list
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
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: The code example in onSpinWait() Javadoc

JSR166 Concurrency mailing list
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 <[hidden email]> 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
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: The code example in onSpinWait() Javadoc

JSR166 Concurrency mailing list

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 <[hidden email]> 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
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: The code example in onSpinWait() Javadoc

JSR166 Concurrency mailing list
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 <[hidden email]> 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 <[hidden email]> 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
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: The code example in onSpinWait() Javadoc

JSR166 Concurrency mailing list
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, <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: The code example in onSpinWait() Javadoc

JSR166 Concurrency mailing list
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 <[hidden email]> 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, <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: The code example in onSpinWait() Javadoc

JSR166 Concurrency mailing list
I would like to hear the opinion of Gil Gene about it too: AFAIK he was the one (or one of many?) that has proposed it to be included in http://openjdk.java.net/jeps/285

Il gio 14 nov 2019, 23:22 Francesco Nigro <[hidden email]> ha scritto:
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 <[hidden email]> 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, <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: The code example in onSpinWait() Javadoc

JSR166 Concurrency mailing list
Gil Tene* Android typo error 

Il gio 14 nov 2019, 23:28 Francesco Nigro <[hidden email]> ha scritto:
I would like to hear the opinion of Gil Gene about it too: AFAIK he was the one (or one of many?) that has proposed it to be included in http://openjdk.java.net/jeps/285

Il gio 14 nov 2019, 23:22 Francesco Nigro <[hidden email]> ha scritto:
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 <[hidden email]> 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, <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: The code example in onSpinWait() Javadoc

JSR166 Concurrency mailing list
In reply to this post by JSR166 Concurrency mailing list
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, <[hidden email]> 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 <[hidden email]> 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, <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: The code example in onSpinWait() Javadoc

JSR166 Concurrency mailing list
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 <[hidden email]> 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, <[hidden email]> 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 <[hidden email]> 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, <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: The code example in onSpinWait() Javadoc

JSR166 Concurrency mailing list
In reply to this post by JSR166 Concurrency mailing list
I guess I'm missing something about the starting point in this thread. What do you find "half baked"
about the actual example in the Javadoc? It's one of the common use cases (with no time-based
backoffs) in various applications (ones that e.g. dedicate a spinning thread on a dedicated core).

E.g. https://github.com/LMAX-Exchange/disruptor/blob/5764f3b01faab603322c61cede957b7e79f58c8b/src/main/java/com/lmax/disruptor/BusySpinWaitStrategy.java

There are obviously additional common variants, some of which include backoff mechanisms
(time based, count based, phase of moon based, etc.), but IMO there is no "right way" to do this,
and a no-backoff use case is just as valid (and maybe even common) as one that includes a
backoff. The code carefully avoids spelling out how "eventNotificationNotReceived" is determined.
Hey, the event may even be a backoff timeout...

Would a more detailed/complicated/opinionated example of a specific backoff flavor would help
make the meaning and use of the method more clear, or help point out caveats or pitfalls better?

> On Nov 14, 2019, at 2:28 PM, Francesco Nigro via Concurrency-interest <[hidden email]> wrote:
>
> Gil Tene* Android typo error
>
> Il gio 14 nov 2019, 23:28 Francesco Nigro <[hidden email]> ha scritto:
> I would like to hear the opinion of Gil Gene about it too: AFAIK he was the one (or one of many?) that has proposed it to be included in http://openjdk.java.net/jeps/285
>
> Il gio 14 nov 2019, 23:22 Francesco Nigro <[hidden email]> ha scritto:
> 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 <[hidden email]> 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, <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
> _______________________________________________
> Concurrency-interest mailing list
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

signature.asc (849 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: The code example in onSpinWait() Javadoc

JSR166 Concurrency mailing list
Hi Gil,

It's one of the common use cases
:) Although I can say the same I'm not quite sure that is that common and your example re LMAX makes it even more clear (not that mine on JCTools is better eh!)
On the other hand, onSpinWait itself is equally uncommon on j.u.c., so I take all your points re the existing doc.

Would a more detailed/complicated/opinionated example of a specific backoff flavor would help
make the meaning and use of the method more clear, or help point out caveats or pitfalls better?
My (personal) fear is that users will recognize the general busy spin loop pattern, thinking that given that the JVM "is able to optmize it" (thanks to help of unicorns and rainbows too) and 
making it a much more attractive pairs of scissors to play with then before :)
 

Il giorno ven 15 nov 2019 alle ore 06:38 Gil Tene <[hidden email]> ha scritto:
I guess I'm missing something about the starting point in this thread. What do you find "half baked"
about the actual example in the Javadoc? It's one of the common use cases (with no time-based
backoffs) in various applications (ones that e.g. dedicate a spinning thread on a dedicated core).

E.g. https://github.com/LMAX-Exchange/disruptor/blob/5764f3b01faab603322c61cede957b7e79f58c8b/src/main/java/com/lmax/disruptor/BusySpinWaitStrategy.java

There are obviously additional common variants, some of which include backoff mechanisms
(time based, count based, phase of moon based, etc.), but IMO there is no "right way" to do this,
and a no-backoff use case is just as valid (and maybe even common) as one that includes a
backoff. The code carefully avoids spelling out how "eventNotificationNotReceived" is determined.
Hey, the event may even be a backoff timeout...

Would a more detailed/complicated/opinionated example of a specific backoff flavor would help
make the meaning and use of the method more clear, or help point out caveats or pitfalls better?

> On Nov 14, 2019, at 2:28 PM, Francesco Nigro via Concurrency-interest <[hidden email]> wrote:
>
> Gil Tene* Android typo error
>
> Il gio 14 nov 2019, 23:28 Francesco Nigro <[hidden email]> ha scritto:
> I would like to hear the opinion of Gil Gene about it too: AFAIK he was the one (or one of many?) that has proposed it to be included in http://openjdk.java.net/jeps/285
>
> Il gio 14 nov 2019, 23:22 Francesco Nigro <[hidden email]> ha scritto:
> 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 <[hidden email]> 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, <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
> _______________________________________________
> Concurrency-interest mailing list
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: The code example in onSpinWait() Javadoc

JSR166 Concurrency mailing list
By "half-baked" I meant specifically that the example could be valid but only under specific conditions, such as core-pinned thread, or backoff timeout event, etc. However, the "mundane" class and method names which are chosen ("EventHandler") may mislead users into thinking that spin-loop is a good go-to strategy to waiting for some conditions/logic executed, instead of using a synchronization primitive or attaching a listener to a CompletableFuture/ListeanableFuture if one is involved.

I like Francesco's example because it is self-contained and doesn't need any backoff, so the complicated discussion of the tradeoffs involved and conditions which should be accounted for (typical wait time, GC algorithm, busyness of the system, etc.) could be blissfully omitted.

On Fri, 15 Nov 2019 at 11:05, Francesco Nigro via Concurrency-interest <[hidden email]> wrote:
Hi Gil,

It's one of the common use cases
:) Although I can say the same I'm not quite sure that is that common and your example re LMAX makes it even more clear (not that mine on JCTools is better eh!)
On the other hand, onSpinWait itself is equally uncommon on j.u.c., so I take all your points re the existing doc.

Would a more detailed/complicated/opinionated example of a specific backoff flavor would help
make the meaning and use of the method more clear, or help point out caveats or pitfalls better?
My (personal) fear is that users will recognize the general busy spin loop pattern, thinking that given that the JVM "is able to optmize it" (thanks to help of unicorns and rainbows too) and 
making it a much more attractive pairs of scissors to play with then before :)
 

Il giorno ven 15 nov 2019 alle ore 06:38 Gil Tene <[hidden email]> ha scritto:
I guess I'm missing something about the starting point in this thread. What do you find "half baked"
about the actual example in the Javadoc? It's one of the common use cases (with no time-based
backoffs) in various applications (ones that e.g. dedicate a spinning thread on a dedicated core).

E.g. https://github.com/LMAX-Exchange/disruptor/blob/5764f3b01faab603322c61cede957b7e79f58c8b/src/main/java/com/lmax/disruptor/BusySpinWaitStrategy.java

There are obviously additional common variants, some of which include backoff mechanisms
(time based, count based, phase of moon based, etc.), but IMO there is no "right way" to do this,
and a no-backoff use case is just as valid (and maybe even common) as one that includes a
backoff. The code carefully avoids spelling out how "eventNotificationNotReceived" is determined.
Hey, the event may even be a backoff timeout...

Would a more detailed/complicated/opinionated example of a specific backoff flavor would help
make the meaning and use of the method more clear, or help point out caveats or pitfalls better?

> On Nov 14, 2019, at 2:28 PM, Francesco Nigro via Concurrency-interest <[hidden email]> wrote:
>
> Gil Tene* Android typo error
>
> Il gio 14 nov 2019, 23:28 Francesco Nigro <[hidden email]> ha scritto:
> I would like to hear the opinion of Gil Gene about it too: AFAIK he was the one (or one of many?) that has proposed it to be included in http://openjdk.java.net/jeps/285
>
> Il gio 14 nov 2019, 23:22 Francesco Nigro <[hidden email]> ha scritto:
> 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 <[hidden email]> 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, <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
> _______________________________________________
> Concurrency-interest mailing list
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: The code example in onSpinWait() Javadoc

JSR166 Concurrency mailing list
It would be interesting to have an onSpinWait(long nanos) version ehich can be intrinsified if need be to provide the most accurate delay based on the underlying system.

Talking about time being meaningless in a non-RT OS is rather meaningless in itself—we’re relying on getting CPU timeslices before the end of the universe anyway ;)

On Fri, 15 Nov 2019 at 12:06, Roman Leventov via Concurrency-interest <[hidden email]> wrote:
By "half-baked" I meant specifically that the example could be valid but only under specific conditions, such as core-pinned thread, or backoff timeout event, etc. However, the "mundane" class and method names which are chosen ("EventHandler") may mislead users into thinking that spin-loop is a good go-to strategy to waiting for some conditions/logic executed, instead of using a synchronization primitive or attaching a listener to a CompletableFuture/ListeanableFuture if one is involved.

I like Francesco's example because it is self-contained and doesn't need any backoff, so the complicated discussion of the tradeoffs involved and conditions which should be accounted for (typical wait time, GC algorithm, busyness of the system, etc.) could be blissfully omitted.

On Fri, 15 Nov 2019 at 11:05, Francesco Nigro via Concurrency-interest <[hidden email]> wrote:
Hi Gil,

It's one of the common use cases
:) Although I can say the same I'm not quite sure that is that common and your example re LMAX makes it even more clear (not that mine on JCTools is better eh!)
On the other hand, onSpinWait itself is equally uncommon on j.u.c., so I take all your points re the existing doc.

Would a more detailed/complicated/opinionated example of a specific backoff flavor would help
make the meaning and use of the method more clear, or help point out caveats or pitfalls better?
My (personal) fear is that users will recognize the general busy spin loop pattern, thinking that given that the JVM "is able to optmize it" (thanks to help of unicorns and rainbows too) and 
making it a much more attractive pairs of scissors to play with then before :)
 

Il giorno ven 15 nov 2019 alle ore 06:38 Gil Tene <[hidden email]> ha scritto:
I guess I'm missing something about the starting point in this thread. What do you find "half baked"
about the actual example in the Javadoc? It's one of the common use cases (with no time-based
backoffs) in various applications (ones that e.g. dedicate a spinning thread on a dedicated core).

E.g. https://github.com/LMAX-Exchange/disruptor/blob/5764f3b01faab603322c61cede957b7e79f58c8b/src/main/java/com/lmax/disruptor/BusySpinWaitStrategy.java

There are obviously additional common variants, some of which include backoff mechanisms
(time based, count based, phase of moon based, etc.), but IMO there is no "right way" to do this,
and a no-backoff use case is just as valid (and maybe even common) as one that includes a
backoff. The code carefully avoids spelling out how "eventNotificationNotReceived" is determined.
Hey, the event may even be a backoff timeout...

Would a more detailed/complicated/opinionated example of a specific backoff flavor would help
make the meaning and use of the method more clear, or help point out caveats or pitfalls better?

> On Nov 14, 2019, at 2:28 PM, Francesco Nigro via Concurrency-interest <[hidden email]> wrote:
>
> Gil Tene* Android typo error
>
> Il gio 14 nov 2019, 23:28 Francesco Nigro <[hidden email]> ha scritto:
> I would like to hear the opinion of Gil Gene about it too: AFAIK he was the one (or one of many?) that has proposed it to be included in http://openjdk.java.net/jeps/285
>
> Il gio 14 nov 2019, 23:22 Francesco Nigro <[hidden email]> ha scritto:
> 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 <[hidden email]> 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, <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
> _______________________________________________
> Concurrency-interest mailing list
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
--
Cheers,

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: The code example in onSpinWait() Javadoc

JSR166 Concurrency mailing list
In reply to this post by JSR166 Concurrency mailing list
I also think that providing an example of a SpinLock, as per David's suggestion, would be better than the current example because it would implicitly communicate (explicit communication could be added as well) that onSpinWait() is a low-level tool mostly for implementors of concurrency utilities rather than typical concurrent code. While the discussion for when it would be appropriate to use the resulting SpinLock class could be omitted. Or implied that it's a simplified version of ReentrantLock, not intended for actual use (similarly to Mutex example in the documentation for AbstractQueuedSynchronizer).

On Fri, 15 Nov 2019 at 13:04, Roman Leventov <[hidden email]> wrote:
By "half-baked" I meant specifically that the example could be valid but only under specific conditions, such as core-pinned thread, or backoff timeout event, etc. However, the "mundane" class and method names which are chosen ("EventHandler") may mislead users into thinking that spin-loop is a good go-to strategy to waiting for some conditions/logic executed, instead of using a synchronization primitive or attaching a listener to a CompletableFuture/ListeanableFuture if one is involved.

I like Francesco's example because it is self-contained and doesn't need any backoff, so the complicated discussion of the tradeoffs involved and conditions which should be accounted for (typical wait time, GC algorithm, busyness of the system, etc.) could be blissfully omitted.

On Fri, 15 Nov 2019 at 11:05, Francesco Nigro via Concurrency-interest <[hidden email]> wrote:
Hi Gil,

It's one of the common use cases
:) Although I can say the same I'm not quite sure that is that common and your example re LMAX makes it even more clear (not that mine on JCTools is better eh!)
On the other hand, onSpinWait itself is equally uncommon on j.u.c., so I take all your points re the existing doc.

Would a more detailed/complicated/opinionated example of a specific backoff flavor would help
make the meaning and use of the method more clear, or help point out caveats or pitfalls better?
My (personal) fear is that users will recognize the general busy spin loop pattern, thinking that given that the JVM "is able to optmize it" (thanks to help of unicorns and rainbows too) and 
making it a much more attractive pairs of scissors to play with then before :)
 

Il giorno ven 15 nov 2019 alle ore 06:38 Gil Tene <[hidden email]> ha scritto:
I guess I'm missing something about the starting point in this thread. What do you find "half baked"
about the actual example in the Javadoc? It's one of the common use cases (with no time-based
backoffs) in various applications (ones that e.g. dedicate a spinning thread on a dedicated core).

E.g. https://github.com/LMAX-Exchange/disruptor/blob/5764f3b01faab603322c61cede957b7e79f58c8b/src/main/java/com/lmax/disruptor/BusySpinWaitStrategy.java

There are obviously additional common variants, some of which include backoff mechanisms
(time based, count based, phase of moon based, etc.), but IMO there is no "right way" to do this,
and a no-backoff use case is just as valid (and maybe even common) as one that includes a
backoff. The code carefully avoids spelling out how "eventNotificationNotReceived" is determined.
Hey, the event may even be a backoff timeout...

Would a more detailed/complicated/opinionated example of a specific backoff flavor would help
make the meaning and use of the method more clear, or help point out caveats or pitfalls better?

> On Nov 14, 2019, at 2:28 PM, Francesco Nigro via Concurrency-interest <[hidden email]> wrote:
>
> Gil Tene* Android typo error
>
> Il gio 14 nov 2019, 23:28 Francesco Nigro <[hidden email]> ha scritto:
> I would like to hear the opinion of Gil Gene about it too: AFAIK he was the one (or one of many?) that has proposed it to be included in http://openjdk.java.net/jeps/285
>
> Il gio 14 nov 2019, 23:22 Francesco Nigro <[hidden email]> ha scritto:
> 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 <[hidden email]> 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, <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
> _______________________________________________
> Concurrency-interest mailing list
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: The code example in onSpinWait() Javadoc

JSR166 Concurrency mailing list
In reply to this post by JSR166 Concurrency mailing list
Let's start with why you wouldn't just park nanos. Because you want the CPU to do something useful instead of idling.

For a time limit to be implementable for arbitrary useful things, the computation done by onSpinWait must know how much time that computation will take - maybe to choose the computation of the right size. Gödel says hello.

Or you should be able to suspend that computation at arbitrary points. Well, not in Java.

Alex

On Fri, 15 Nov 2019, 10:25 Viktor Klang via Concurrency-interest, <[hidden email]> wrote:
It would be interesting to have an onSpinWait(long nanos) version ehich can be intrinsified if need be to provide the most accurate delay based on the underlying system.

Talking about time being meaningless in a non-RT OS is rather meaningless in itself—we’re relying on getting CPU timeslices before the end of the universe anyway ;)

On Fri, 15 Nov 2019 at 12:06, Roman Leventov via Concurrency-interest <[hidden email]> wrote:
By "half-baked" I meant specifically that the example could be valid but only under specific conditions, such as core-pinned thread, or backoff timeout event, etc. However, the "mundane" class and method names which are chosen ("EventHandler") may mislead users into thinking that spin-loop is a good go-to strategy to waiting for some conditions/logic executed, instead of using a synchronization primitive or attaching a listener to a CompletableFuture/ListeanableFuture if one is involved.

I like Francesco's example because it is self-contained and doesn't need any backoff, so the complicated discussion of the tradeoffs involved and conditions which should be accounted for (typical wait time, GC algorithm, busyness of the system, etc.) could be blissfully omitted.

On Fri, 15 Nov 2019 at 11:05, Francesco Nigro via Concurrency-interest <[hidden email]> wrote:
Hi Gil,

It's one of the common use cases
:) Although I can say the same I'm not quite sure that is that common and your example re LMAX makes it even more clear (not that mine on JCTools is better eh!)
On the other hand, onSpinWait itself is equally uncommon on j.u.c., so I take all your points re the existing doc.

Would a more detailed/complicated/opinionated example of a specific backoff flavor would help
make the meaning and use of the method more clear, or help point out caveats or pitfalls better?
My (personal) fear is that users will recognize the general busy spin loop pattern, thinking that given that the JVM "is able to optmize it" (thanks to help of unicorns and rainbows too) and 
making it a much more attractive pairs of scissors to play with then before :)
 

Il giorno ven 15 nov 2019 alle ore 06:38 Gil Tene <[hidden email]> ha scritto:
I guess I'm missing something about the starting point in this thread. What do you find "half baked"
about the actual example in the Javadoc? It's one of the common use cases (with no time-based
backoffs) in various applications (ones that e.g. dedicate a spinning thread on a dedicated core).

E.g. https://github.com/LMAX-Exchange/disruptor/blob/5764f3b01faab603322c61cede957b7e79f58c8b/src/main/java/com/lmax/disruptor/BusySpinWaitStrategy.java

There are obviously additional common variants, some of which include backoff mechanisms
(time based, count based, phase of moon based, etc.), but IMO there is no "right way" to do this,
and a no-backoff use case is just as valid (and maybe even common) as one that includes a
backoff. The code carefully avoids spelling out how "eventNotificationNotReceived" is determined.
Hey, the event may even be a backoff timeout...

Would a more detailed/complicated/opinionated example of a specific backoff flavor would help
make the meaning and use of the method more clear, or help point out caveats or pitfalls better?

> On Nov 14, 2019, at 2:28 PM, Francesco Nigro via Concurrency-interest <[hidden email]> wrote:
>
> Gil Tene* Android typo error
>
> Il gio 14 nov 2019, 23:28 Francesco Nigro <[hidden email]> ha scritto:
> I would like to hear the opinion of Gil Gene about it too: AFAIK he was the one (or one of many?) that has proposed it to be included in http://openjdk.java.net/jeps/285
>
> Il gio 14 nov 2019, 23:22 Francesco Nigro <[hidden email]> ha scritto:
> 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 <[hidden email]> 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, <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
> _______________________________________________
> Concurrency-interest mailing list
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
--
Cheers,
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
12