Spec-Zone.ru › C++

std::atomic_compare_exchange_weak, std::atomic_compare_exchange_strong, std::atomic_compare_exchange_weak_explicit, std::atomic_compare_exchange_strong_explicit

Определено в заголовке <atomic>
template< class T >
bool atomic_compare_exchange_weak
    ( std::atomic<T>* obj, typename std::atomic<T>::value_type* expected,
      typename std::atomic<T>::value_type desired ) noexcept;
(1) (с C++11)
template< class T >
bool atomic_compare_exchange_weak
    ( volatile std::atomic<T>* obj,
      typename std::atomic<T>::value_type* expected,
      typename std::atomic<T>::value_type desired ) noexcept;
(2) (с C++11)
template< class T >
bool atomic_compare_exchange_strong
    ( std::atomic<T>* obj, typename std::atomic<T>::value_type* expected,
      typename std::atomic<T>::value_type desired ) noexcept;
(3) (с C++11)
template< class T >
bool atomic_compare_exchange_strong
    ( volatile std::atomic<T>* obj,
      typename std::atomic<T>::value_type* expected, 
      typename std::atomic<T>::value_type desired ) noexcept;
(4) (с C++11)
template< class T >
bool atomic_compare_exchange_weak_explicit
    ( std::atomic<T>* obj, typename std::atomic<T>::value_type* expected, 
      typename std::atomic<T>::value_type desired,
      std::memory_order success, std::memory_order failure ) noexcept;
(5) (с C++11)
template< class T >
bool atomic_compare_exchange_weak_explicit
    ( volatile std::atomic<T>* obj,
      typename std::atomic<T>::value_type* expected, 
      typename std::atomic<T>::value_type desired,
      std::memory_order success, std::memory_order failure ) noexcept;
(6) (с C++11)
template< class T >
bool atomic_compare_exchange_strong_explicit
    ( std::atomic<T>* obj, typename std::atomic<T>::value_type* expected, 
      typename std::atomic<T>::value_type desired,
      std::memory_order success, std::memory_order failure ) noexcept;
(7) (с C++11)
template< class T >
bool atomic_compare_exchange_strong_explicit
    ( volatile std::atomic<T>* obj,
      typename std::atomic<T>::value_type* expected, 
      typename std::atomic<T>::value_type desired,
      std::memory_order success, std::memory_order failure ) noexcept;
(8) (с C++11)

Атомарно сравнивает представление объекта(до C++20)представление значения(с C++20) объекта, на который указывает obj с представлением объекта, на который указывает expected, и, если они битово-равны, заменяет первое на desired (выполняет операцию read-modify-write). В противном случае загружает фактическое значение, на которое указывает obj в *expected (выполняет операцию загрузки).

Перегрузки Модель памяти для
операции read‑modify‑write операции загрузки
(1-4) std::memory_order_seq_cst std::memory_order_seq_cst
(5-8) success failure

Эти функции определяются через члены функции std::atomic.

1,2) obj->compare_exchange_weak(*expected, desired)
3,4) obj->compare_exchange_strong(*expected, desired)
5,6) obj->compare_exchange_weak(*expected, desired, success, failure)
7,8) obj->compare_exchange_strong(*expected, desired, success, failure)

Если failure сильнее, чем success или(до C++17) является одним из std::memory_order_release и std::memory_order_acq_rel, поведение является неопределённым.

Параметры

obj - указатель на атомарный объект для проверки и изменения
expected - указатель на значение, ожидаемое в атомарном объекте
desired - значение, которое необходимо сохранить в атомарном объекте, если оно ожидаемое
success - порядок синхронизации памяти для операции read-modify-write, если сравнение прошло успешно
failure - порядок синхронизации памяти для операции загрузки, если сравнение не прошло успешно

Возвращаемое значение

Результат сравнения: true если *obj было равно *expected, false в противном случае.

Примечания

std::atomic_compare_exchange_weak и std::atomic_compare_exchange_weak_explicit (слабые версии) могут случайно терпяться неудачу, то есть действовать так, как если бы *obj != *expected , даже если они равны. Когда сравнение-и-обмен находится в цикле, они будут обеспечивать лучшую производительность на некоторых платформах.

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

Для объединения с битами, которые участвуют в представлении значений некоторых членов, но не других, сравнение-и-обмен может всегда терпяться неудачей, потому что такие биты заполнения имеют неопределённые значения, когда они не участвуют в представлении значения активного члена.

Биты заполнения, которые никогда не участвуют в представлении значения объекта, игнорируются.

(с C++20)

Пример

Операции сравнения-и-обмена часто используются в качестве основных строительных блоков для атомарных структур данных.

#include <atomic>
 
template<class T>
struct node
{
    T data;
    node* next;
    node(const T& data) : data(data), next(nullptr) {}
};
 
template<class T>
class stack
{
    std::atomic<node<T>*> head;
public:
    void push(const T& data)
    {
        node<T>* new_node = new node<T>(data);
 
        // put the current value of head into new_node->next
        new_node->next = head.load(std::memory_order_relaxed);
 
        // now make new_node the new head, but if the head
        // is no longer what's stored in new_node->next
        // (some other thread must have inserted a node just now)
        // then put that new head into new_node->next and try again
        while (!std::atomic_compare_exchange_weak_explicit(
                   &head, &new_node->next, new_node,
                   std::memory_order_release, std::memory_order_relaxed))
            ; // the body of the loop is empty
// note: the above loop is not thread-safe in at least
// GCC prior to 4.8.3 (bug 60272), clang prior to 2014-05-05 (bug 18899)
// MSVC prior to 2014-03-17 (bug 819819). See member function version for workaround
    }
};
 
int main()
{
    stack<int> s;
    s.push(1);
    s.push(2);
    s.push(3);
}

Отчёты об ошибках

Следующие отчёты об ошибках, изменяющие поведение, были применены ретроактивно к ранее опубликованным стандартам C++.

DR Применимо к Поведение, опубликованное Правильное поведение
P0558R1 C++11 требовалось точное совпадение типов, потому что
T был выведен из нескольких аргументов
T выводится только
из obj

См. также

compare_exchange_weakcompare_exchange_strong
атомарно сравнивает значение атомарного объекта с неатомарным аргументом и выполняет атомарный обмен, если они равны, или атомарную загрузку, если нет
(общедоступный член-функция std::atomic<T>)
atomic_exchangeatomic_exchange_explicit
(C++11)(C++11)
атомарно заменяет значение атомарного объекта неатомарным аргументом и возвращает старое значение атомарного
(шаблон функции)
std::atomic_compare_exchange_weak(std::shared_ptr) std::atomic_compare_exchange_strong(std::shared_ptr)
(устарело в C++20)
специализирует атомарные операции для std::shared_ptr
(шаблон функции)
C документация для atomic_compare_exchange, atomic_compare_exchange_explicit

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/atomic/atomic_compare_exchange

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API