Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend atomic compare_and_swap #1443

Merged
merged 4 commits into from
Feb 18, 2016

Conversation

Amanieu
Copy link
Member

@Amanieu Amanieu commented Jan 5, 2016

@nrc nrc added the T-libs-api Relevant to the library API team, which will review and decide on the RFC. label Jan 5, 2016
@alexcrichton alexcrichton self-assigned this Jan 21, 2016
@alexcrichton
Copy link
Member

For some history, we currently auto-calculate the second ordering when emitting an LLVM instruction for this, which was added in rust-lang/rust@30ff17f8 when upgrading LLVM and it happened to start requiring two orderings. I don't believe we ever revisited that this until just now! Also for reference, the LLVM documentation for the cmpxchg instruction is here. I do agree that it's kinda unfortunate that compare_and_swap is already taken (without the ability to define a failure ordering), but alas!

Alright, so with all that out of the way, here are some thoughts of mine:

  • We may want to decide whether to consider the existing compare_and_swap method deprecated or not. This may involve a literal #[rustc_deprecated], but it may not. If we do consider it deprecated, then we could avoid adding compare_and_swap_weak_explicit (wow that's a mouthful), and we could also consider renaming compare_and_swap entirely (for example compare_exchange like C++ does). The downside of this, however, is that compare_and_swap is clearly more ergonomic as it only requires one ordering and is perhaps easier to think about as well.
  • Could you add documentation to the RFC to indicate what happens if the two orderings are invalid? For example if the failure ordering is stronger than the success one that should be considered invalid. I suspect that a panic is sufficient here (as the orderings are almost always statically known) and this mirrors the fence function as well.
  • I agree that adding new functions is superior to adding more options to the Ordering enum which only make sense for compare_and_swap. This also has backwards-compatibility issues with adding variants to a stable enum
  • One other possibility for an alternative would be to have a totally separate enum for the "double ordering" methods. This enum could then have all possible combinations.
  • One further possibility would be to make the method generic over a trait to get the orderings, for example:
pub trait IntoTwoOrderings {
    pub fn into_two_orderings(self) -> (Ordering, Ordering);
}

impl IntoTwoOrderings for Ordering {
    pub fn into_two_orderings(self) -> (Ordering, Ordering) { (self, self) }
}

impl IntoTwoOrderings for (Ordering, Ordering) {
    pub fn into_two_orderings(self) -> (Ordering, Ordering) { self }
}

pub fn compare_and_swap<O: IntoTwoOrderings>(&self, expected: T, ordering: O) -> T;

Alright, now with all that out of the way, my personal opinion is that we should stick with this RFC basically as-is. I think that there's utility in keeping the one-ordering methods as they're somewhat easier to understand, and adding lots of methods won't really hurt the types.

That being said I'm not super certain about one alternative over the other, I'm just swaying a bit in that direction.

@Amanieu
Copy link
Member Author

Amanieu commented Jan 22, 2016

I don't think adding hacks to extend the Ordering enum is very viable, especially since a separate function is going to be required anyways to preserve backward compatibility. We might as well just use two Ordering arguments in that case.

I disagree that a single Ordering parameter is more ergonomic: either you know what you are doing, in which case you know which memory orderings to use, or you just use SeqCst everywhere. Most C++ code uses both ordering parameters on compare_exchange, so lock-free code ported from C++ will most likely specify both ordering.

I'm actually starting to prefer the idea of simply deprecating compare_and_swap and replacing it with a compare_exchange that allows specifying both ordering parameters.

@alexcrichton
Copy link
Member

In C++ though it looks like you've at least got the option of not specifying a second ordering? (I may be misunderstanding overloading...)

If it's idiomatic in C++, however, to always have two orderings then I'd be pretty ok pushing on deprecation + new names for the new functions

@Amanieu
Copy link
Member Author

Amanieu commented Jan 23, 2016

In C++ though it looks like you've at least got the option of not specifying a second ordering? (I may be misunderstanding overloading...)

That is correct, C++ gives you 3 options: no ordering (defaults to seqcst), single ordering (failure defaults to the strongest possible) or both orderings.

If it's idiomatic in C++, however, to always have two orderings then I'd be pretty ok pushing on deprecation + new names for the new functions

To be precise, in C++ it is idiomatic to either specify both orderings or none at all. But I've never really seen any code that just specifies a single ordering. If you look at C11, it only provides forms that accept no orderings or both.

I've updated the RFC to propose deprecating compare_and_swap and replacing it with compare_exchange_strong and compare_exchange_weak.

@ranma42 ranma42 mentioned this pull request Jan 23, 2016
@alexcrichton
Copy link
Member

Thanks for the update! This is looking pretty good to me. I might slightly prefer compare_exchange to compare_exchange_strong, but that's just a minor bikeshed.

@alexcrichton
Copy link
Member

🔔 This RFC is now entering its week-long final comment period 🔔

Note that this is deprecating the compare_and_swap function, so others may indeed have some opinions!


My own personal opinion here is that I would prefer the name compare_exchange over the name compare_exchange_strong, but otherwise looks good to me!

@alexcrichton alexcrichton added the final-comment-period Will be merged/postponed/closed in ~10 calendar days unless new substational objections are raised. label Feb 11, 2016
@aturon
Copy link
Member

aturon commented Feb 11, 2016

My own personal opinion here is that I would prefer the name compare_exchange over the name compare_exchange_strong, but otherwise looks good to me!

Same here.

@briansmith
Copy link

Please use the ISO C11 and/or ISO C++ names and semantics whenever possible. Otherwise, it would be a complete mess to understand code where more than one language (Rust, C, C++) is being used to modify the same value using atomic primitives. The ISO C and C++ stuff isn't perfect, but people are working hard to get them to be closer to perfect and there's no need to reinvent the wheel or to generate confusion with different names or slightly different semantics for similarly-named things.

@nagisa
Copy link
Member

nagisa commented Feb 13, 2016

Otherwise, it would be a complete mess to understand code where more than one language (Rust, C, C++) is being used to modify the same value using atomic primitives.

I do not find this argument persuading. __sync_*_compare_and_swap (C), atomic::compare_exchange_stronk (c++), Atomic*::compareAndSet (java) and Atomic*::{compare_and_swap,compare_exchange} (rust, this rfc) are all pretty different from the naming standpoint already (don’t even match between C and C++!). They all intuitively seem to mean the same thing (with the exception of whatever the meaning strong in the c++ API is supposed to carry).

For the weak CAS, I’d rather use java style naming (appending/prepending weak only to the weak variant) and leaving off strong on the regular version.

@briansmith
Copy link

I do not find this argument persuading. _sync*_compare_and_swap (C), atomic::compare_exchange_stronk (c++),

C11 uses the same names as C++11 for these, except they prefixed atomic_ to them due to C's poor namespacing issues. See http://en.cppreference.com/w/c/atomic/atomic_compare_exchange.

@Amanieu
Copy link
Member Author

Amanieu commented Feb 15, 2016

I would prefer atomic_compare_exchange_strong for consistency with C++, but I don't feel too strongly either way.

@alexcrichton
Copy link
Member

The libs team discussed this RFC during triage yesterday and the conclusion was that we'd like to merge! We felt, however, that the name compare_exchange was more "rustic" over compare_exchange_strong. @Amanieu would you be ok updating this to mention that name instead? After that I can merge.

@Amanieu
Copy link
Member Author

Amanieu commented Feb 18, 2016

Done

@alexcrichton alexcrichton merged commit 9638c35 into rust-lang:master Feb 18, 2016
bors added a commit to rust-lang/rust that referenced this pull request Feb 22, 2016
@Centril Centril added A-sync Synchronization related proposals & ideas A-sync-atomics Atomics related proposals & ideas A-intrinsic Proposals relating to intrinsics. labels Nov 23, 2018
Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this pull request Dec 21, 2020
…=Amanieu

Deprecate atomic compare_and_swap method

Finish implementing [RFC 1443](https://github.com/rust-lang/rfcs/blob/master/text/1443-extended-compare-and-swap.md) (rust-lang/rfcs#1443).

It was decided to deprecate `compare_and_swap` [back in Rust 1.12 already](rust-lang#31767 (comment)). I can't find any info about that decision being reverted. My understanding is just that it has been forgotten. If there has been a decision on keeping `compare_and_swap` then it's hard to find, and even if this PR does not go through it can act as a place where people can find out about the decision being reverted.

Atomic operations are hard to understand, very hard. And it does not help that there are multiple similar methods to do compare and swap with. They are so similar that for a reader it might be hard to understand the difference. This PR aims to make that simpler by finally deprecating `compare_and_swap` which is essentially just a more limited version of `compare_exchange`. The documentation is also updated (according to the RFC text) to explain the differences a bit better.

Even if we decide to not deprecate `compare_and_swap`. I still think the documentation for the atomic operations should be improved to better describe their differences and similarities. And the documentation can be written nicer than the PR currently proposes, but I wanted to start somewhere. Most of it is just copied from the RFC.

The documentation for `compare_exchange` and `compare_exchange_weak` indeed describe how they work! The problem is that they are more complex and harder to understand than `compare_and_swap`. So for someone who does not fully grasp this they might fall back to using `compare_and_swap`. Making the documentation outline the similarities and differences might build a bridge for people so they can cross over to the more powerful and sometimes more efficient operations.

The conversions I do to avoid the `std` internal deprecation errors are very straight forward `compare_and_swap -> compare_exchange` changes where the orderings are just using the mapping in the new documentation. Only in one place did I use `compare_exchange_weak`. This can probably be improved further. But the goal here was not for those operations to be perfect. Just to not get worse and to allow the deprecation to happen.
Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this pull request Dec 22, 2020
…=Amanieu

Deprecate atomic compare_and_swap method

Finish implementing [RFC 1443](https://github.com/rust-lang/rfcs/blob/master/text/1443-extended-compare-and-swap.md) (rust-lang/rfcs#1443).

It was decided to deprecate `compare_and_swap` [back in Rust 1.12 already](rust-lang#31767 (comment)). I can't find any info about that decision being reverted. My understanding is just that it has been forgotten. If there has been a decision on keeping `compare_and_swap` then it's hard to find, and even if this PR does not go through it can act as a place where people can find out about the decision being reverted.

Atomic operations are hard to understand, very hard. And it does not help that there are multiple similar methods to do compare and swap with. They are so similar that for a reader it might be hard to understand the difference. This PR aims to make that simpler by finally deprecating `compare_and_swap` which is essentially just a more limited version of `compare_exchange`. The documentation is also updated (according to the RFC text) to explain the differences a bit better.

Even if we decide to not deprecate `compare_and_swap`. I still think the documentation for the atomic operations should be improved to better describe their differences and similarities. And the documentation can be written nicer than the PR currently proposes, but I wanted to start somewhere. Most of it is just copied from the RFC.

The documentation for `compare_exchange` and `compare_exchange_weak` indeed describe how they work! The problem is that they are more complex and harder to understand than `compare_and_swap`. So for someone who does not fully grasp this they might fall back to using `compare_and_swap`. Making the documentation outline the similarities and differences might build a bridge for people so they can cross over to the more powerful and sometimes more efficient operations.

The conversions I do to avoid the `std` internal deprecation errors are very straight forward `compare_and_swap -> compare_exchange` changes where the orderings are just using the mapping in the new documentation. Only in one place did I use `compare_exchange_weak`. This can probably be improved further. But the goal here was not for those operations to be perfect. Just to not get worse and to allow the deprecation to happen.
Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this pull request Dec 22, 2020
…=Amanieu

Deprecate atomic compare_and_swap method

Finish implementing [RFC 1443](https://github.com/rust-lang/rfcs/blob/master/text/1443-extended-compare-and-swap.md) (rust-lang/rfcs#1443).

It was decided to deprecate `compare_and_swap` [back in Rust 1.12 already](rust-lang#31767 (comment)). I can't find any info about that decision being reverted. My understanding is just that it has been forgotten. If there has been a decision on keeping `compare_and_swap` then it's hard to find, and even if this PR does not go through it can act as a place where people can find out about the decision being reverted.

Atomic operations are hard to understand, very hard. And it does not help that there are multiple similar methods to do compare and swap with. They are so similar that for a reader it might be hard to understand the difference. This PR aims to make that simpler by finally deprecating `compare_and_swap` which is essentially just a more limited version of `compare_exchange`. The documentation is also updated (according to the RFC text) to explain the differences a bit better.

Even if we decide to not deprecate `compare_and_swap`. I still think the documentation for the atomic operations should be improved to better describe their differences and similarities. And the documentation can be written nicer than the PR currently proposes, but I wanted to start somewhere. Most of it is just copied from the RFC.

The documentation for `compare_exchange` and `compare_exchange_weak` indeed describe how they work! The problem is that they are more complex and harder to understand than `compare_and_swap`. So for someone who does not fully grasp this they might fall back to using `compare_and_swap`. Making the documentation outline the similarities and differences might build a bridge for people so they can cross over to the more powerful and sometimes more efficient operations.

The conversions I do to avoid the `std` internal deprecation errors are very straight forward `compare_and_swap -> compare_exchange` changes where the orderings are just using the mapping in the new documentation. Only in one place did I use `compare_exchange_weak`. This can probably be improved further. But the goal here was not for those operations to be perfect. Just to not get worse and to allow the deprecation to happen.
bors added a commit to rust-lang-ci/rust that referenced this pull request Dec 23, 2020
…manieu

Deprecate atomic compare_and_swap method

Finish implementing [RFC 1443](https://github.com/rust-lang/rfcs/blob/master/text/1443-extended-compare-and-swap.md) (rust-lang/rfcs#1443).

It was decided to deprecate `compare_and_swap` [back in Rust 1.12 already](rust-lang#31767 (comment)). I can't find any info about that decision being reverted. My understanding is just that it has been forgotten. If there has been a decision on keeping `compare_and_swap` then it's hard to find, and even if this PR does not go through it can act as a place where people can find out about the decision being reverted.

Atomic operations are hard to understand, very hard. And it does not help that there are multiple similar methods to do compare and swap with. They are so similar that for a reader it might be hard to understand the difference. This PR aims to make that simpler by finally deprecating `compare_and_swap` which is essentially just a more limited version of `compare_exchange`. The documentation is also updated (according to the RFC text) to explain the differences a bit better.

Even if we decide to not deprecate `compare_and_swap`. I still think the documentation for the atomic operations should be improved to better describe their differences and similarities. And the documentation can be written nicer than the PR currently proposes, but I wanted to start somewhere. Most of it is just copied from the RFC.

The documentation for `compare_exchange` and `compare_exchange_weak` indeed describe how they work! The problem is that they are more complex and harder to understand than `compare_and_swap`. So for someone who does not fully grasp this they might fall back to using `compare_and_swap`. Making the documentation outline the similarities and differences might build a bridge for people so they can cross over to the more powerful and sometimes more efficient operations.

The conversions I do to avoid the `std` internal deprecation errors are very straight forward `compare_and_swap -> compare_exchange` changes where the orderings are just using the mapping in the new documentation. Only in one place did I use `compare_exchange_weak`. This can probably be improved further. But the goal here was not for those operations to be perfect. Just to not get worse and to allow the deprecation to happen.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-intrinsic Proposals relating to intrinsics. A-sync Synchronization related proposals & ideas A-sync-atomics Atomics related proposals & ideas final-comment-period Will be merged/postponed/closed in ~10 calendar days unless new substational objections are raised. T-libs-api Relevant to the library API team, which will review and decide on the RFC.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants