Search code examples
rustatomic

Why is there one `Atomic*` type for many primitive type instead of a generic `Atomic<T>`?


Looking at the std::sync::atomic module, one can see a bunch of different Atomic* types, like AtomicU32, AtomicI16 and more. Why is that?

Rust has generics and – as I see it – it would be possible to add a generic Atomic<T> where T is bounded by some trait defined in the module (in Java-ish naming: Atomicable). That trait would be implemented by the types that could be handled in an atomic fashion and users could just use Atomic<u32> instead of AtomicU32.

Why isn't there a generic Atomic<T>? Why have a bunch of different types instead?


Solution

  • The purpose of having an AtomicU8 (for example) is using the underlying hardware to perform atomic instructions, e.g. on x86 the CMPXCHG instruction.

    The original RFC #1505 suggested a Atomic<T> type. One of the main concern was, that people would use T in an unintended way, e.g. using Atomic<[u8; 32]> which would not be possible to support, because of the lack of hardware that support those.
    A fallback/workaround by using a Mutex was proposed, but it felt like cheating, because the compiler would behave differently for different Ts.

    It was finally closed in favor of RFC #1543 which introduced the Atomic{I,U}{8,16,32,64} types we know today.

    It was then implemented in PR #33048 and stabilized in PR #56753 which is Rust 1.34.0.

    To ensure, that the underlying hardware really supports the atomic operations the types are having a cfg attribute, e.g. for AtomicI8 it is #[cfg(target_has_atomic = "8")], for AtomicI16 it is #[cfg(target_has_atomic = "16")] etcetera.