如何在多线程c ++ 17程序中交换两个指针?

时间:2019-02-06 15:53:48

标签: c++ multithreading c++17

我有两个指针:pA和pB。他们指向两个大的哈希图对象。 当pB指向的哈希图完全更新时,我想交换pB和pA。

在C ++ 17中,如何快速交换它们并确保线程安全?原子?我是c ++ 17的新手。

4 个答案:

答案 0 :(得分:7)

可以通过以下方式实现2个指针的原子无等待交换:

#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);
}

需要获取/释放内存顺序,以确保对共享数据T的写入不会在exchange之后重新排序。

答案 1 :(得分:1)

在x86-64上,仅当两个指针在内存中相邻并且直接通过cmpxchg16b指令或通过使用libatomic_ops对齐到16个字节时,才能原子交换2个指针:

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;
}

如果cmpxchg16b不可用,则需要使用互斥锁来交换2个指针。

答案 2 :(得分:0)

也许不仅仅是交换应该是原子的,交易还应该包括检查是否应该进行交换(is_the_hash_map_pointed_by_pB_updated_completely())。 可能应该保护哈希映射,使其不与互斥锁同时使用。

答案 3 :(得分:-3)

std::atomic::exchange

似乎只是为此而设计。

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

例如:

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