I have two pointers which point to a big graph object in a multi-threading C++ app. I try to swap them every 5 minutes. Which way is safe and has the best performance? Is C++11
Does the swap need to be atomic? i.e. do you need to guarantee that another thread cannot observe them both having the same value while swapping?
If you don't need to guarantee the swap is atomic then just use two std::atomic<T*>
objects and swap them using a temporary:
T* tmp = p1;
p1 = p2.load();
p2 = tmp;
If you need the swap to be atomic then to do it in standard C++ you will need to store them both in the same structure, so it can be updated in a single step e.g.
struct TwoPointers { T* p1; T* p2; }
std::atomic<TwoPointers> p;
then you can swap them like so:
auto old = p.load();
p = { old.p2, old.p1 };
This uses double-word atomic operations, which might be implemented with a mutex behind the scenes, so the simple assignment via a temporary is likely to perform better, but I doubt it will make any difference once every five minutes.
Both versions above assume only one thread will try to swap them at any time, because although loading the old value is done atomically, and writing the new value is done atomically, there is a window between those two steps during which another thread could change the pointer values. If that's a problem use a std::atomic<TwoPointers>
like this instead:
auto old = p.load();
while (!p.compare_exchange_strong(old, { old.p2, old.p1 }))
{ };
Using compare_exchange_strong
in a loop is slightly slower than a single atomic store, but again you won't notice the difference if it only happens once every five minutes.
This TwoPointers
solutions also mean the two pointers share a cache-line, but if they are read-only apart from the swap every five minutes then that's not a problem.