API request for JSR166, AtomicMarkableReference

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

API request for JSR166, AtomicMarkableReference

Josh Humphries
I've used AtomicMarkableReference in a couple of places, and I feel its API really falls short for what I've been doing.

The methods it exposes seem to imply some intended semantics on how the mark relates to the reference. However, in the cases I've used it, I'm really trying to store a reference and a flag together -- so the flag isn't a "mark" that relates to the reference, rather they are two (independent?) elements that I need to update atomically and whose "shape" fits that of the markable reference.

So I'm inclined to make these requests to simplify my own usage. I'm curious what others think:
  • Exposing the internal [ref, boolean] tuple type and deprecating the APIs that require callers to construct and pass in a boolean array would make much joy. E.g.:
MarkedReference<T> get();
@Deprecated T get(boolean[] markHolder);
  • This class is missing atomic get-and-set mechanisms:
T getAndSetReference(T newValue);
boolean getAndSetMark(boolean newMark);
MarkedReference<T> getAndSet(T newValue, boolean newMark);
  • This class is also missing the complement of attemptMark:
boolean attemptSet(boolean expectedMark, T newValue);
  • Finally, a reliable attemptMark (that returns false only when the value does not match expected; never spuriously) would certainly be a nice to have. I find myself having to wrap the existing method in a CAS-style loop every single time to get the behavior I actually need. (Same goes for the attemptSet operation requested above.)
I'm curious about others that might use this class and what they think about the above API amendments. Are my use cases far from the norm or were these operations just overlooked when the class was originally created?

I'm tempted to just write my own thing on top of AtomicReference to do what I need. But it feels a little like "reinventing the wheel" when there's a standard API class that is so close just not quite..

----
Josh Humphries
Manager, Shared Systems  |  Platform Engineering
Atlanta, GA  |  678-400-4867

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

Re: API request for JSR166, AtomicMarkableReference

David Holmes-6

Hi Josh,
 
I think you are trying to make this class something it is not. It is not a general purpose API for managing two distinct entities as an atomic pair. What it was abstractly representing was the situation where you can steal a "mark" bit from a reference and so treat it as a "reference plus a mark bit". This is useful in algorithms that would ideally like a CAS2 (atomic CAS of 2 independent variables) but can be degenerately written using CAS if the bits for the second variable can be colocated within the bits of the first - specifically if a reference/pointer is suitably aligned then you can utilise the low order bit(s).
 
The Pair type that is used is purely an internal representation detail for a cross-platform implementation - a "real" implementation would use native code or Unsafe to directly manipulate the mark bit within the object reference. Given the "mark" bit is intended to tell you something about the reference itself it really doesn't make sense to set the reference indepedent of the mark bit ala your attemptSet method.
 
I do agree though that attemptMark failing spuriously seems odd - I don't recall why we did that.
 
Cheers,
David
-----Original Message-----
From: [hidden email] [mailto:[hidden email]]On Behalf Of Josh Humphries
Sent: Wednesday, 1 April 2015 2:10 PM
To: [hidden email]
Subject: [concurrency-interest] API request for JSR166,AtomicMarkableReference

I've used AtomicMarkableReference in a couple of places, and I feel its API really falls short for what I've been doing.

The methods it exposes seem to imply some intended semantics on how the mark relates to the reference. However, in the cases I've used it, I'm really trying to store a reference and a flag together -- so the flag isn't a "mark" that relates to the reference, rather they are two (independent?) elements that I need to update atomically and whose "shape" fits that of the markable reference.

So I'm inclined to make these requests to simplify my own usage. I'm curious what others think:
  • Exposing the internal [ref, boolean] tuple type and deprecating the APIs that require callers to construct and pass in a boolean array would make much joy. E.g.:
MarkedReference<T> get();
@Deprecated T get(boolean[] markHolder);
  • This class is missing atomic get-and-set mechanisms:
T getAndSetReference(T newValue);
boolean getAndSetMark(boolean newMark);
MarkedReference<T> getAndSet(T newValue, boolean newMark);
  • This class is also missing the complement of attemptMark:
boolean attemptSet(boolean expectedMark, T newValue);
  • Finally, a reliable attemptMark (that returns false only when the value does not match expected; never spuriously) would certainly be a nice to have. I find myself having to wrap the existing method in a CAS-style loop every single time to get the behavior I actually need. (Same goes for the attemptSet operation requested above.)
I'm curious about others that might use this class and what they think about the above API amendments. Are my use cases far from the norm or were these operations just overlooked when the class was originally created?

I'm tempted to just write my own thing on top of AtomicReference to do what I need. But it feels a little like "reinventing the wheel" when there's a standard API class that is so close just not quite..

----
Josh Humphries
Manager, Shared Systems  |  Platform Engineering
Atlanta, GA  |  678-400-4867

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

Re: API request for JSR166, AtomicMarkableReference

Josh Humphries
Thanks for the reply, David!

To me, that doesn't sound like strong reasons to not have some of the suggested API, like get-and-set operations at the least (they seem like a natural additions to complement set and compareAndSet operations).

As far as the tuple type, do any JVMs actually provide intrinsics in the way you suggest? For example, does HotSpot special case this class? If so, I guess it must also have special-casing in garbage collection so it knows to mask off the mark bits when computing the live set.

The tuple type still would be better API. Having the caller construct an array is ugly and less natural/intuitive when reading the code. The class already has to unpack the ref and the mark. It's just a matter of re-packaging into an object instead of splitting it into a return value and an array-write.

Maybe instead of deprecating the existing get(boolean[]), it could just have another method that returns a tuple type. (If not now, surely this will be strongly considered once Project Valhalla is mainstream... Java 10 maybe?).

As far as the unreliable attemptMark, I'm sure it's because a reliable version cannot be done without a loop. But, as I mentioned before, I end up writing that loop in my own code. So it would be nice to have something in the API to reduce boiler-plate at call-sites.




----
Josh Humphries
Manager, Shared Systems  |  Platform Engineering
Atlanta, GA  |  678-400-4867

On Wed, Apr 1, 2015 at 12:37 AM, David Holmes <[hidden email]> wrote:
Hi Josh,
 
I think you are trying to make this class something it is not. It is not a general purpose API for managing two distinct entities as an atomic pair. What it was abstractly representing was the situation where you can steal a "mark" bit from a reference and so treat it as a "reference plus a mark bit". This is useful in algorithms that would ideally like a CAS2 (atomic CAS of 2 independent variables) but can be degenerately written using CAS if the bits for the second variable can be colocated within the bits of the first - specifically if a reference/pointer is suitably aligned then you can utilise the low order bit(s).
 
The Pair type that is used is purely an internal representation detail for a cross-platform implementation - a "real" implementation would use native code or Unsafe to directly manipulate the mark bit within the object reference. Given the "mark" bit is intended to tell you something about the reference itself it really doesn't make sense to set the reference indepedent of the mark bit ala your attemptSet method.
 
I do agree though that attemptMark failing spuriously seems odd - I don't recall why we did that.
 
Cheers,
David
-----Original Message-----
From: [hidden email] [mailto:[hidden email]]On Behalf Of Josh Humphries
Sent: Wednesday, 1 April 2015 2:10 PM
To: [hidden email]
Subject: [concurrency-interest] API request for JSR166,AtomicMarkableReference

I've used AtomicMarkableReference in a couple of places, and I feel its API really falls short for what I've been doing.

The methods it exposes seem to imply some intended semantics on how the mark relates to the reference. However, in the cases I've used it, I'm really trying to store a reference and a flag together -- so the flag isn't a "mark" that relates to the reference, rather they are two (independent?) elements that I need to update atomically and whose "shape" fits that of the markable reference.

So I'm inclined to make these requests to simplify my own usage. I'm curious what others think:
  • Exposing the internal [ref, boolean] tuple type and deprecating the APIs that require callers to construct and pass in a boolean array would make much joy. E.g.:
MarkedReference<T> get();
@Deprecated T get(boolean[] markHolder);
  • This class is missing atomic get-and-set mechanisms:
T getAndSetReference(T newValue);
boolean getAndSetMark(boolean newMark);
MarkedReference<T> getAndSet(T newValue, boolean newMark);
  • This class is also missing the complement of attemptMark:
boolean attemptSet(boolean expectedMark, T newValue);
  • Finally, a reliable attemptMark (that returns false only when the value does not match expected; never spuriously) would certainly be a nice to have. I find myself having to wrap the existing method in a CAS-style loop every single time to get the behavior I actually need. (Same goes for the attemptSet operation requested above.)
I'm curious about others that might use this class and what they think about the above API amendments. Are my use cases far from the norm or were these operations just overlooked when the class was originally created?

I'm tempted to just write my own thing on top of AtomicReference to do what I need. But it feels a little like "reinventing the wheel" when there's a standard API class that is so close just not quite..

----
Josh Humphries
Manager, Shared Systems  |  Platform Engineering
Atlanta, GA  |  <a href="tel:678-400-4867" value="+16784004867" target="_blank">678-400-4867


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