How to atomically copy types that are not-trivially copyable

I’m writing an Atom class, for types T are not trivially-copyable. I was wondering if my below implementation of load() and store() could cause a race condition.

class Atom {
    // Assumptions:
    // 1. atomic<T> is not natively supported
    // 2. T does not contain any interior-pointers (pointers pointing to a field
    //    in the structure or the struct itself)
    // 3. T is neither trivially-copyable nor trivially-destructible
    // 4. T's copy constructor is thread-safe; i.e. The object being copied is not
    //    mutated without synchronization.

    using LT = typename std::aligned_storage<sizeof(T), alignof(T)>::type;

    spin::MRSWLock<T> locked_object;  // a multiple-reader-single-writer spinlock

    template<class... Args, class = std::enable_if_t<std::is_constructible_v<T, Args...>>>
    explicit Atom(Args&&... args): locked_object(std::forward<Args>(args)...) {}

    T load() const {
        LT l;
        {
            auto x = locked_object.read(); // get read lock

            // make a bitwise/shallow copy of object
            l = reinterpret_cast<const LT*>(&*x);

        } // object unlocked here when x goes out of scope

        // make a deep copy of the object here by calling copy constructor.
        return T(*reinterpret_cast<const T*>(&l));
    }

    template<class... Args, class = std::enable_if_t<std::is_constructible_v<T, Args...>>>
    void store(Args&&... args) const {
        LT l, m;
        // construct the new object
        new (&l) T(std::forward<Args>(args)...);
        {
            auto x = locked_object.write(); // get write lock

            // make a bitwise-copy of the current object
            m = reinterpret_cast<const LT*>(&*x);

            // make bitwise-assign of the new value of the object
            *reinterpret_cast<LT*>(&*x) = l;

        }// object unlocked here as x goes out of scope

        // destroy old object here.
        reinterpret_cast<T*>(&m)->~T();
    }
};

If a race condition is possible, is there a way to copy the object without calling its copy constructor while it’s locked?

Source: Windows Questions C++

LEAVE A COMMENT