I mean, I don’t think that's true in this case. Both forms generate the same instruction on x86 (lock cmpxchg for both). Godbolt: https://godbolt.org/z/vcMK9j6WP (And it appears to be identical on ARM64 as well.)
> If you’re using this kind of thing, it’s specifically because performance really matters and you want to avoid that synchronized compare and exchange that a mutex uses.
A full fence is not any less expensive than a seq-cst cmpxchg.
Do you have any idea why Java is missing acq-rel cmpxchg? I know they are late to the reasonable memory model party but it seems like an odd choice not to just import the C++ memory model wholesale. It's proved to be a decent model in practice!
About C++ using the same instruction for both, that’s up to their implementation. There’s no requirement that the more relaxed atomics actually be more relaxed. Only that the stronger atomics don’t permit more relaxed behavior.
There may also be other requirements in the spec, that I’m not aware of, that require using the strong compare exchange.
It’s been years since I’ve done any substantial lock free programming, I may be remembering incorrectly.
The paper you cite proposed compiling an atomic add-zero to MFENCE+MOV, which is 5 times slower than the rest of the seqlock access, just because fences were not in Java at the time and are "a very difficult-to-use and C++11/C11-specific construct". That part of the paper has never made sense to me, and certainly does not matter now that Java has fences. Just wrap the seqlock into a primitive that hides the fence and call it a day.
>> you want the readers to be able to read multiple values atomically. I read this in TFA, and interpreted it to mean you could read multiple values atomically, which would be an answer to your question - mutexes only protect one thing and you can't combine them atomically.
But looking at the code, it seems that this does no better? It only allows reading of multiple values insofar as it protects one hard-coded struct which happens to have multiple fields.
Obviously you could just use a mutex. This may perform better under some workloads, especially if writes are very rare.