Jak można zsynchronizować interakcję między wątkami?
sobes.tech AI
Odpowiedź od AI
Istnieje kilka głównych mechanizmów synchronizacji wątków w C++:
-
Muteksy (Mutexes): Zapewniają wzajemne wykluczanie. Tylko jeden wątek może posiadać mutex w danym momencie. Używane do ochrony wspólnych zasobów przed równoczesnym dostępem.
#include <mutex> std::mutex myMutex; void criticalSection() { std::lock_guard<std::mutex> lock(myMutex); // Zdobycie mutexa // Praca z zasobem wspólnym } // Mutex jest automatycznie zwalniany po wyjściu z zakresu -
Semafory: Kontrolują dostęp do ograniczonej liczby zasobów. Semafor ma licznik wskazujący liczbę dostępnych zasobów. Wątki mogą zmniejszać (aby uzyskać zasób) lub zwiększać (aby zwolnić).
#include <semaphore.h> // Zazwyczaj używany w systemach POSIX sem_t mySemaphore; void initSemaphore(int count) { sem_init(&mySemaphore, 0, count); // Inicjalizacja semafora z licznikiem count } void acquireResource() { sem_wait(&mySemaphore); // Zmniejsza licznik, blokuje jeśli jest 0 // Użycie zasobu } void releaseResource() { sem_post(&mySemaphore); // Zwiększa licznik } -
Zmienne warunkowe (Condition Variables): Pozwalają wątkom oczekiwać na określony warunek. Zazwyczaj używane razem z mutexami. Wątek oczekujący zwalnia mutex i blokuje się do momentu, gdy inny wątek go powiadomi o spełnieniu warunku.
#include <condition_variable> #include <mutex> #include <queue> std::condition_variable myCondition; std::mutex myMutex; std::queue<int> myQueue; void producer(int value) { std::lock_guard<std::mutex> lock(myMutex); myQueue.push(value); myCondition.notify_one(); // Powiadomienie oczekującego wątku } int consumer() { std::unique_lock<std::mutex> lock(myMutex); myCondition.wait(lock, [&]{ return !myQueue.empty(); }); // Oczekiwanie na warunek int value = myQueue.front(); myQueue.pop(); return value; } -
Zmienne atomowe (Atomic Variables): Pozwalają na wykonywanie prostych operacji (odczyt, zapis, modyfikacja) atomowo, bez konieczności używania mutexów dla tych operacji.
#include <atomic> std::atomic_int atomicCounter(0); void incrementCounter() { atomicCounter++; // Atomowe zwiększenie } -
Bariery (Barriers): Synchronizują kilka wątków tak, aby żaden nie mógł kontynuować, dopóki wszyscy nie osiągną bariery.
#include <barrier> // C++20 std::barrier myBarrier(3); // Bariera dla 3 wątków void workerThread() { // Wykonanie części pracy myBarrier.arrive_and_wait(); // Oczekiwanie na wszystkich wątków przy barierze // Wykonanie kolejnej części pracy }
Wybór konkretnego mechanizmu zależy od charakteru interakcji między wątkami:
- Muteksy: Najczęstszy sposób ochrony wspólnych danych.
- Semafory: Zarządzanie dostępem do ograniczonych zasobów.
- Zmienne warunkowe: Oczekiwanie na wystąpienie określonego zdarzenia lub stanu.
- Zmienne atomowe: Efektywne wykonywanie prostych, atomowych operacji.
- Bariery: Synchronizacja wątków do wspólnego przejścia do kolejnego etapu.