How to swap two pointers in multi-threaded c++ 17 program?

扶醉桌前 提交于 2019-12-22 01:18:23

问题


I have two pointers: pA and pB. They points to two big hash map objects. when the hash map pointed by pB is updated completely, I want to swap pB and pA.

In C++ 17, how to swap them fast and thread safe? Atomic? I am new to c++ 17.


回答1:


Atomic wait-free exchange of 2 pointers can be implemented in the following manner:

#include <atomic>
#include <cstdint>
#include <cassert>

template<class T>
class Pointers2 {
    uintptr_t const ab_;
    std::atomic<uintptr_t> a_;

public:
    Pointers2(T* a, T* b)
        : ab_(reinterpret_cast<uintptr_t>(a) ^ reinterpret_cast<uintptr_t>(b))
        , a_(reinterpret_cast<uintptr_t>(a))
    {}

    T* a() const { return reinterpret_cast<T*>(a_.load(std::memory_order_acquire)); }
    T* b() const { return reinterpret_cast<T*>(a_.load(std::memory_order_acquire) ^ ab_); }
    void exchange() { a_.fetch_xor(ab_, std::memory_order_release); }
};

int main() {
    int a = 1, b = 2;
    Pointers2<int> p2(&a, &b);
    assert(p2.a() == &a);
    assert(p2.b() == &b);
    p2.exchange();
    assert(p2.a() == &b);
    assert(p2.b() == &a);
    p2.exchange();
    assert(p2.a() == &a);
    assert(p2.b() == &b);
}

Acquire/release memory ordering is required to make sure that writes to shared data T do not get reordered past exchange.




回答2:


On x86-64 you can atomically exchange 2 pointers only if they are adjacent in memory and aligned to 16 bytes with cmpxchg16b instruction directly or by using libatomic_ops:

AO_INLINE int
AO_compare_double_and_swap_double_full(volatile AO_double_t *addr,
                                       AO_t old_val1, AO_t old_val2,
                                       AO_t new_val1, AO_t new_val2)
{
  char result;
  __asm__ __volatile__("lock; cmpxchg16b %0; setz %1"
                      : "=m"(*addr), "=a"(result)
                      : "m"(*addr), "d" (old_val2), "a" (old_val1),
                        "c" (new_val2), "b" (new_val1)
                      : "memory");
  return (int) result;
}

If cmpxchg16b is unavailable you need to use a mutex to make exchanging 2 pointers atomic.




回答3:


Maybe it's not just swap that should be atomic, but transaction should include check that swap should be made (is_the_hash_map_pointed_by_pB_updated_completely()). Probably hash maps should be protected from concurrent usage with mutex.




回答4:


std::atomic::exchange

seems to be designed just for that.

http://www.cplusplus.com/reference/atomic/atomic/exchange/

For example:

std::atomic<int*> ptr1;
std::atomic<int*> ptr2;
ptr1.exchange(ptr2);


来源:https://stackoverflow.com/questions/54557611/how-to-swap-two-pointers-in-multi-threaded-c-17-program

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!