Как поменять местами два указателя в многопоточной программе c ++ 17? - PullRequest
0 голосов
/ 06 февраля 2019

У меня есть два указателя: pA и pB.Они указывают на два больших объекта хэш-карты.когда хэш-карта, на которую указывает pB, полностью обновлена, я хочу поменять местами pB и pA.

В C ++ 17 как их поменять быстро и поточно-ориентированно?Atomic?Я новичок в C ++ 17.

Ответы [ 4 ]

0 голосов
/ 06 февраля 2019

Возможно, это не просто своп, который должен быть атомарным, а транзакция должна включать проверку того, что своп должен быть выполнен (is_the_hash_map_pointed_by_pB_updated_completely ()).Вероятно, хеш-карты должны быть защищены от одновременного использования с мьютексом.

0 голосов
/ 06 февраля 2019
std::atomic::exchange

, похоже, предназначен именно для этого.

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

Например:

std::atomic<int*> ptr1;
std::atomic<int*> ptr2;
ptr1.exchange(ptr2);
0 голосов
/ 06 февраля 2019

Атомарный обмен 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.

0 голосов
/ 06 февраля 2019

На x86-64 вы можете атомарно обмениваться 2 указателями, только если они смежны в памяти и выровнены по 16 байтов с помощью инструкции cmpxchg16b напрямую или с помощью 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;
}

Если cmpxchg16b недоступен, вам нужно использовать мьютекс, чтобы сделать обмен 2 указателями атомарными.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...