Search code examples
c++c++11atomic

Can two std::atomic's be part of one union?


I want to do this:

union {
    std::atomic<uint128_t> u128;
    struct {
        std::atomic<uint64_t> u64_1;
        std::atomic<uint64_t> u64_2;
    };
};

Several threads will read and write both parts of the union.

Is it safe?

Edit: I use Linux, x86_64, clang 3.3

Edit2: I want to be able to increment and decrement u64_1, read u64_2, and write u128 (compare_exchange)

Edit3: What if I use atomic builtin functions? The union will look like this:

union {
    uint128_t u128;
    struct {
        uint64_t u64_1;
        uint64_t u64_2;
    };
};

u64_1 will map to first half of u128 and u64_2 will map to second half.


Solution

  • The std::atomic<T> operations can be either lockless or locking, depending on whether the architecture offers the underlying guarantees. You can check this by checking std::atomic<T>::is_lock_free().

    If the type is not lock free, it might be supported by the library by means of a counter. That in turn probably means that the type is no longer a POD underneath, which in turn means that it is your responsibility to call the constructors/destructors when switching from one active member of the union to another.

    If there is a mutex for the 128 bit but not the 64bit types you might end up with a situation in which the layout of the values coincides, but the atomicity of operations is guaranteed by different means, so it might seem to work, but fail spuriously and in a way that is hard to even detect.