0Pricing
C++ Academy · Lekcja

Wzorce compare-and-swap (CAS)

Implementuj bezblokadowe aktualizacje za pomocą compare_exchange_weak i compare_exchange_strong

Wzorce compare-and-swap (CAS) to bezpłatna lekcja C++ Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej C++ Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs C++ Academy zawiera 4 lekcji w sumie.

Prymityw CAS

Compare-and-swap atomowo odczytuje, porównuje i warunkowo zapisuje wartość. To podstawa większości algorytmów bezblokadowych.

Compare exchange w C++

Dwa warianty w std::atomic:

  • compare_exchange_strong(expected, desired) — kończy się powodzeniem, gdy bieżąca wartość jest równa expected
  • compare_exchange_weak(expected, desired) — może zakończyć się pozorną porażką

Budowa pętli CAS

Klasyczna pętla CAS: odczytaj, oblicz, spróbuj zapisać. Ponów próbę, jeśli inny wątek wygrał wyścig.

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

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

CAS do atomowej aktualizacji

Użyj CAS, gdy nowa wartość zależy od starej. Zwykły store spowodowałby utratę aktualizacji wykonanych przez współbieżne wątki.

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

Stos bezblokadowy: push

Proste dodawanie elementu do stosu bezblokadowego używa CAS do umieszczenia nowego węzła na szczycie stosu.

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));
}

Pozorna porażka

compare_exchange_weak może zakończyć się niepowodzeniem nawet wtedy, gdy wartości są zgodne — na przykład na platformach takich jak ARM, gdzie podstawowa instrukcja może zakończyć się niepowodzeniem. Używaj go w pętlach; wariantu strong, gdy ponawianie próby jest kosztowne.

Wzorzec aktualizacji: reset

Aby zresetować wartość do znanego stanu tylko wtedy, gdy nie została zmieniona.

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

Element budulcowy: licznik atomowy

W przypadku zwykłego licznika fetch_add jest prostszy i szybszy niż pętla CAS.

Element budulcowy: flaga atomowa

W przypadku prostej flagi logicznej std::atomic_flag jest lżejszy niż std::atomic<bool> i obsługuje test_and_set.

Analizowanie współbieżności

Kod bezblokadowy słynie z tego, że trudno go analizować. Stosuj rygorystyczne testy (TSan, fuzzing), modele formalne, gdy są dostępne, i preferuj sprawdzone implementacje.

Kiedy wybrać CAS

Użyj CAS, gdy:

  • Wiele wątków często aktualizuje tę samą wartość
  • Mutexy stają się wąskim gardłem z powodu rywalizacji
  • Sekcja krytyczna jest bardzo krótka i prosta

Kiedy nie używać CAS

Unikaj CAS, gdy:

  • Aktualizacja wymaga więcej niż kilku operacji
  • Poprawność jest ważniejsza niż przepustowość
  • Zespół nie ma doświadczenia w programowaniu bezblokadowym

Szybkie sprawdzenie

Dlaczego zazwyczaj używamy compare_exchange_weak wewnątrz pętli?

Podsumowanie

Compare-and-swap atomowo aktualizuje wartość tylko wtedy, gdy jest ona równa oczekiwanej wartości. Pętle CAS obsługują współbieżne aktualizacje bez blokad. Używaj compare_exchange_weak w pętlach, a wariantu strong przy jednorazowych próbach.

Często zadawane pytania

Czy lekcja „Wzorce compare-and-swap (CAS)” jest bezpłatna?

Tak — pełny tekst „Wzorce compare-and-swap (CAS)” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu C++ Academy, przejdź na CoddyKit PRO. Kurs C++ Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Wzorce compare-and-swap (CAS)”?

Implementuj bezblokadowe aktualizacje za pomocą compare_exchange_weak i compare_exchange_strong Ćwiczysz C++ Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć C++ Academy?

Nie wymagamy żadnego doświadczenia. C++ Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.

Ile czasu zajmuje lekcja „Wzorce compare-and-swap (CAS)”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji C++ Academy?

Tak. Każda lekcja C++ Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. std::atomic i porządki pamięci
  2. Wzorce compare-and-swap (CAS)
  3. Implementacja kolejki bezblokadowej
  4. Wskaźniki hazardowe i problem ABA
← Powrót do C++ Academy