3 ms·
> The obvious choice is a compare-and-swap atomic, which will fail if another thread has already made the transition. However, with a more careful selection of
by comex 3y ago
> The obvious choice is a compare-and-swap atomic, which will fail if another thread has already made the transition. However, with a more careful selection of state representation, we can do this with just an atomic increment!
But why? Atomic increments and compare-and-swap have the same performance on most hardware, and this is a cold path so it wouldn't matter if they didn't. Using a compare-and-swap you would only need one byte to store your "once" object rather than a whole int.
- inetknght 3y ago> Using a compare-and-swap you would only need one byte to store your "once" object rather than a whole int. But after alignment requirements of anything around it, it will likely be the size of the platform's natural int anyway
- BeeOnRope 3y agoYes because of the "it's the cold of path" aspect. That said, CAS is often considerably slower than an atomic increment replacement even if the usual sources report equal throughout because the dependency chains to both the output value and flags (i.e., the "succeeded?" indicator) usually involves a load of the value, and an operation to manipulate it prior to using it in the CAS. So even if a CAS never fails it can end up half a dozen cycles slower if this chain matters (and it often does). That aspect fails to be captured by say uops.info which just tries to isolate the effect of the instruction alone. Of, course, the even more important reason to use unconditional ops on a contended path if you can is that they don't fail: CAS retries will be significant in that case (but this doesn't apply here because "one off cold path").