Пространства имён
Варианты
Действия

std::atomic::compare_exchange_weak, std::atomic::compare_exchange_strong

Материал из cppreference.com
 
 
Библиотека атомарных операций
 
 
<tbody> </tbody>
bool compare_exchange_weak( T& expected, T desired, std::memory_order success, std::memory_order failure ) noexcept;
(1) (начиная с C++11)
bool compare_exchange_weak( T& expected, T desired, std::memory_order success, std::memory_order failure ) volatile noexcept;
(2) (начиная с C++11)
bool compare_exchange_weak( T& expected, T desired, std::memory_order order = std::memory_order_seq_cst ) noexcept;
(3) (начиная с C++11)
bool compare_exchange_weak( T& expected, T desired, std::memory_order order = std::memory_order_seq_cst ) volatile noexcept;
(4) (начиная с C++11)
bool compare_exchange_strong( T& expected, T desired, std::memory_order success, std::memory_order failure ) noexcept;
(5) (начиная с C++11)
bool compare_exchange_strong( T& expected, T desired, std::memory_order success, std::memory_order failure ) volatile noexcept;
(6) (начиная с C++11)
bool compare_exchange_strong( T& expected, T desired, std::memory_order order = std::memory_order_seq_cst ) noexcept;
(7) (начиная с C++11)
bool compare_exchange_strong ( T& expected, T desired, std::memory_order order = std::memory_order_seq_cst ) volatile noexcept;
(8) (начиная с C++11)

Атомарно сравнивает представление объекта (до C++20)представление значения (начиная с C++20), хранящееся в *this, с expected, и, если они побитово равны, заменяет первое на desired (выполняет операцию чтение-изменение-запись). Иначе загружает фактическое значение, хранящееся в *this, в expected (выполняет операцию загрузки).

 Перегрузки  Модель памяти для
 операций чтения‑изменения‑записи  операций загрузки
(1,2,5,6) успех неудача
(3,4,7,8) порядок
  • std::memory_order_acquire, если
    order является std::memory_order_acq_rel
  • std::memory_order_relaxed, если
    order является std::memory_order_release
  • иначе order

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

Это устарело, если std::atomic<T>::is_always_lock_free равно false и любые volatile перегрузки участвуют в разрешении перегрузки.

(начиная с C++20)

Параметры

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

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

true, если внутреннее значение атомарного объекта было изменено, иначе false.

Примечания

Сравнение и копирование происходят побитово (аналогично функциям std::memcmp и std::memcpy) без вызовов конструкторов, операторов присваивания или сравнения.

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

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

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

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

(начиная с C++20)

Примеры

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

#include <atomic>
template<typename T>
struct node
{
    T data;
    node* next;
    node(const T& data) : data(data), next(nullptr) {}
};

template<typename T>
class stack
{
    std::atomic<node<T>*> head;
 public:
    void push(const T& data)
    {
      node<T>* new_node = new node<T>(data);

      // присваиваем текущее значение из head в new_node->next
      new_node->next = head.load(std::memory_order_relaxed);

      // теперь установим new_node новым head, но если head
      // больше не является тем, что хранится в new_node->next
      // (другой поток мог вставить свой new_node прямо сейчас)
      // то присвоим новый head в new_node->next и повторим
      while(!head.compare_exchange_weak(new_node->next, new_node,
                                        std::memory_order_release,
                                        std::memory_order_relaxed))
          ; // тело цикла пустое

// Примечание: код выше не является потокобезопасным по крайней мере в
// GCC до 4.8.3 (ошибка 60272), clang до 2014-05-05 (ошибка 18899)
// MSVC до 2014-03-17 (ошибка 819819). Ниже приводится обходной путь:
//      node<T>* old_head = head.load(std::memory_order_relaxed);
//      do {
//          new_node->next = old_head;
//       } while(!head.compare_exchange_weak(old_head, new_node,
//                                           std::memory_order_release,
//                                           std::memory_order_relaxed));
    }
};
int main()
{
    stack<int> s;
    s.push(1);
    s.push(2);
    s.push(3);
}

Демонстрирует, как std::compare_exchange_strong изменяет значение атомарной переменной или переменной, используемой для сравнения.

#include <atomic>
#include <iostream>

std::atomic<int>  ai;

int  tst_val= 4;
int  new_val= 5;
bool exchanged= false;

void valsout()
{
    std::cout << "ai= " << ai
	      << "  tst_val= " << tst_val
	      << "  new_val= " << new_val
	      << "  exchanged= " << std::boolalpha << exchanged
	      << '\n';
}

int main()
{
    ai= 3;
    valsout();

    // tst_val != ai   ==>  tst_val была изменена
    exchanged = ai.compare_exchange_strong( tst_val, new_val );
    valsout();

    // tst_val == ai   ==>  ai была изменена
    exchanged = ai.compare_exchange_strong( tst_val, new_val );
    valsout();
}

Вывод:

ai= 3  tst_val= 4  new_val= 5  exchanged= false
ai= 3  tst_val= 3  new_val= 5  exchanged= false
ai= 5  tst_val= 3  new_val= 5  exchanged= true

Смотрите также

атомарно сравнивает значение атомарного объекта с неатомарным аргументом и выполняет атомарный обмен, если они равны, или атомарную загрузку, если нет
(шаблон функции) [править]
Morty Proxy This is a proxified and sanitized view of the page, visit original site.