0Pricing
C++ Academy · Урок

Сравнение и обмен: шаблоны CAS

Реализуйте обновления без блокировок с помощью compare_exchange_weak и compare_exchange_strong.

«Сравнение и обмен: шаблоны CAS» — бесплатный урок C++ Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C++ Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C++ Academy содержит 4 уроков всего.

Примитив CAS

Сравнение и обмен атомарно читает значение, сравнивает его и условно записывает новое. Это основа большинства алгоритмов без блокировок.

Сравнение и обмен в C++

Два варианта в std::atomic:

  • compare_exchange_strong(expected, desired) — выполняется успешно, если текущее значение равно expected
  • compare_exchange_weak(expected, desired) — может ошибочно завершиться неудачей

Устройство цикла CAS

Классический цикл CAS: прочитать, вычислить, попытаться записать. Повторите попытку, если другой поток выиграл гонку.

std::atomic<int> a{0};

int old = a.load();
int next;
do {
    next = compute_new(old);
} while (!a.compare_exchange_weak(old, next));

CAS для атомарного обновления

Используйте CAS, когда новое значение зависит от старого. Обычный store потерял бы обновления параллельных потоков.

// Atomic max
int current = a.load();
while (newval > current && !a.compare_exchange_weak(current, newval));

Стек без блокировок: добавление

Простая операция добавления в стек без блокировок использует CAS, чтобы установить новый узел в начале стека.

struct Node { int value; Node* next; };
std::atomic<Node*> head{nullptr};

void push(int v) {
    Node* n = new Node{v, nullptr};
    n->next = head.load();
    while (!head.compare_exchange_weak(n->next, n));
}

Ошибочный сбой

compare_exchange_weak может завершиться неудачей даже при совпадении значений — на таких платформах, как ARM, где базовой инструкции разрешено завершаться неудачей. Используйте его внутри циклов; применяйте strong, если повторная попытка обходится дорого.

Шаблон обновления: сброс

Сбросить значение в известное состояние, только если оно не изменилось.

int expected = 42;
if (a.compare_exchange_strong(expected, 0)) {
    // a was 42 and is now 0
}

Строительный блок: атомарный счётчик

Для обычного счётчика fetch_add проще и быстрее, чем цикл CAS.

Строительный блок: атомарный флаг

Для простого логического флага std::atomic_flag легче, чем std::atomic<bool>, и он поддерживает test_and_set.

Анализ параллельности

Код без блокировок известен своей сложностью для анализа. Используйте тщательное тестирование (TSan, фаззинг), формальные модели, если они доступны, и отдавайте предпочтение уже существующим проверенным реализациям.

Когда выбирать CAS

Используйте CAS, когда:

  • Несколько потоков часто обновляют одно и то же значение
  • Мьютексы становятся узким местом из-за конкуренции
  • Критическая секция очень короткая и простая

Когда не следует использовать CAS

Избегайте CAS, когда:

  • Для обновления требуется больше пары операций
  • Корректность важнее пропускной способности
  • Команде не хватает опыта в программировании без блокировок

Быстрая проверка

Почему мы обычно используем compare_exchange_weak внутри цикла?

Итоги

Сравнение и обмен атомарно обновляет значение только тогда, когда оно равно ожидаемому значению. Циклы CAS обрабатывают параллельные обновления без блокировок. Используйте compare_exchange_weak внутри циклов, а strong — для однократных попыток.

Часто задаваемые вопросы

Урок «Сравнение и обмен: шаблоны CAS» бесплатный?

Да — полный текст урока «Сравнение и обмен: шаблоны CAS» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C++ Academy, подпишись на CoddyKit PRO. Курс C++ Academy содержит 4 уроков всего.

Чему я научусь в уроке «Сравнение и обмен: шаблоны CAS»?

Реализуйте обновления без блокировок с помощью compare_exchange_weak и compare_exchange_strong. Ты практикуешь C++ Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C++ Academy?

Предыдущий опыт не требуется. C++ Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.

Сколько времени занимает урок «Сравнение и обмен: шаблоны CAS»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C++ Academy?

Да. Каждый урок C++ Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. std::atomic и порядок работы с памятью
  2. Сравнение и обмен: шаблоны CAS
  3. Реализация очереди без блокировок
  4. Опасные указатели и проблема ABA
← Назад к C++ Academy