Сравнение и обмен: шаблоны 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)— выполняется успешно, если текущее значение равно expectedcompare_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 — локальная установка не требуется.
Все уроки этого курса
- std::atomic и порядок работы с памятью
- Сравнение и обмен: шаблоны CAS
- Реализация очереди без блокировок
- Опасные указатели и проблема ABA