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 expectedcompare_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
- std::atomic i porządki pamięci
- Wzorce compare-and-swap (CAS)
- Implementacja kolejki bezblokadowej
- Wskaźniki hazardowe i problem ABA