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 (выполняет операцию чтения-модификации-записи). В противном случае загружает фактическое значение, на которое указывает obj, в *expected (выполняет операцию загрузки).

Перегрузки Модель памяти для
операции чтения-модификации-записи операции загрузки
(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 - порядок синхронизации памяти для операции чтения-модификации-записи при успешном сравнении
failure - порядок синхронизации памяти для операции загрузки при неудачном сравнении

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

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

Примечания

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

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

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

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

(начиная с 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)(удалено в C++26)
специализирует атомарные операции для 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/cpp/atomic/atomic_compare_exchange

Spec-Zone.ru

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