Come si può sincronizzare l'interazione tra thread?
sobes.tech AI
Risposta dell'AI
Esistono diversi meccanismi principali di sincronizzazione dei thread in C++:
-
Mutex (Mutua Esclusione): Garantisce l'esclusione mutua. Solo un thread può possedere un mutex alla volta. Viene usato per proteggere risorse condivise da accessi simultanei.
#include <mutex> std::mutex myMutex; void criticalSection() { std::lock_guard<std::mutex> lock(myMutex); // Acquisizione del mutex // Lavoro con risorsa condivisa } // Il mutex viene rilasciato automaticamente all'uscita dallo scope -
Semafori: Controllano l'accesso a risorse limitate. Un semaforo ha un contatore che indica il numero di risorse disponibili. I thread possono decrementare (per ottenere una risorsa) o incrementare (per rilasciare).
#include <semaphore.h> // Usato tipicamente in sistemi POSIX sem_t mySemaphore; void initSemaphore(int count) { sem_init(&mySemaphore, 0, count); // Inizializza il semaforo con il contatore count } void acquireResource() { sem_wait(&mySemaphore); // Decrementa il contatore, blocca se è zero // Uso della risorsa } void releaseResource() { sem_post(&mySemaphore); // Incrementa il contatore } -
Variabili di condizione: Permettono ai thread di attendere che si verifichi una certa condizione. Sono usate insieme ai mutex. Un thread in attesa rilascia il mutex e si blocca fino a quando un altro thread lo notifica che la condizione è soddisfatta.
#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(); // Notifica un thread in attesa } int consumer() { std::unique_lock<std::mutex> lock(myMutex); myCondition.wait(lock, [&]{ return !myQueue.empty(); }); // Attende la condizione int value = myQueue.front(); myQueue.pop(); return value; } -
Variabili atomiche: Permettono di eseguire operazioni semplici (lettura, scrittura, modifica) in modo atomico, senza bisogno di mutex per queste operazioni.
#include <atomic> std::atomic_int atomicCounter(0); void incrementCounter() { atomicCounter++; // Incremento atomico } -
Barriere: Sincronizzano più thread in modo che nessuno possa continuare finché tutti non hanno raggiunto la barriera.
#include <barrier> // C++20 std::barrier myBarrier(3); // Barriera per 3 thread void workerThread() { // Esecuzione di parte del lavoro myBarrier.arrive_and_wait(); // Attende che tutti raggiungano la barriera // Esecuzione della parte successiva del lavoro }
La scelta di un meccanismo specifico dipende dalla natura dell'interazione tra i thread:
- Mutex: Il metodo più comune per proteggere dati condivisi.
- Semafori: Gestione dell'accesso a risorse limitate.
- Variabili di condizione: Attesa che si verifichi un evento o uno stato specifico.
- Variabili atomiche: Esecuzione efficiente di operazioni semplici e atomiche.
- Barriere: Sincronizzazione dei thread per passare insieme alla fase successiva.