Lock-free swap of two unique_ptr<T>

atomic-swap, c++, c++11, lock-free, unique-ptr

Solution

Lock-free swapping of two pointers

It seems there is no general lock-free solution for this problem. To do this, you need a possibility to atomically write new values into two non-continous memory locations. This is called `DCAS`, but it is not available in Intel processors.

Lock-free transfer of ownership

This one is possible, as it is only needed to atomically save new value into `global` and receive its old value. My first idea was to use `CAS` operation. Take a look at the following code to get an idea:

std::atomic<T*> global;

void f() {
   T* local = new T;
   T* temp = nullptr;
   do {
       temp = global;                                                   // 1
   } while(!std::atomic_compare_exchange_weak(&global, &temp, local));  // 2

   delete temp;
}

Steps

- Remember current `global` pointer in `temp`

- Save `local` to `global` if `global` is still equal to `temp` (it wasn't changed by other thread). Try again if this is not true.

Actually, `CAS` is overkill there, as we do not do anything special with old `global` value before it is changed. So, we just can use atomic exchange operation:

std::atomic<T*> global;

void f() {
   T* local = new T;
   T* temp = std::atomic_exchange(&global, local);
   delete temp;
}

See Jonathan's answer for even more short and elegant solution.

Anyway, you will have to write your own smart pointer. You can't use this trick with standard `unique_ptr`.

Problem

Swapping two `unique_ptr`s is not guaranteed to be threadsafe. ``` std::unique_ptr<T> a, b; std::swap(a, b); // not threadsafe ``` Since I need atomic pointer swaps and since I like the ownership handling of `unique_ptr`, is there a simple way to combine them both? Edit: If this is not possible, I am open for alternatives. I at least want to do something like this: ``` threadshared_unique_ptr<T> global; void f() { threadlocal_unique_ptr<T> local(new T(...)); local.swap_content(global); // atomically for global } ``` What is the idiomatic way of doing this in C++11?

Original source