Esercizi Condition Variables C++
Ecco degli esercizi semplici con soluzione per praticare le basi delle condition variables nel threading in C++.
Esercizio 1
Utilizzare una condition variable per sincronizzare l'accesso a una risorsa condivisa tra due thread.
#include <iostream>#include <thread>#include <mutex>#include <condition_variable>
std::mutex mtx;std::condition_variable cv;bool pronto = false;int dato = 0;
void produttore() { std::unique_lock<std::mutex> lock(mtx); dato = 42; pronto = true; cv.notify_one();}
void consumatore() { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, []{ return pronto; }); std::cout << "Dato ricevuto: " << dato << std::endl;}
int main() { std::thread t1(produttore); std::thread t2(consumatore);
t1.join(); t2.join();
return 0;}
Esercizio 2
Implementare una coda thread-safe utilizzando condition variables.
#include <iostream>#include <queue>#include <thread>#include <mutex>#include <condition_variable>
template <typename T>class CodaThreadSafe {private: std::queue<T> coda; std::mutex mtx; std::condition_variable cv;public: void push(T val) { std::unique_lock<std::mutex> lock(mtx); coda.push(val); cv.notify_one(); }
T pop() { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, [this]{ return !coda.empty(); }); T val = coda.front(); coda.pop(); return val; }};
CodaThreadSafe<int> coda;
void produttore() { for (int i = 0; i < 5; ++i) { coda.push(i); std::cout << "Prodotto: " << i << std::endl; std::this_thread::sleep_for(std::chrono::milliseconds(100)); }}
void consumatore() { for (int i = 0; i < 5; ++i) { int val = coda.pop(); std::cout << "Consumato: " << val << std::endl; }}
int main() { std::thread t1(produttore); std::thread t2(consumatore);
t1.join(); t2.join();
return 0;}
Esercizio 3
Utilizzare una condition variable per implementare un semplice semaforo.
#include <iostream>#include <thread>#include <mutex>#include <condition_variable>
class Semaforo {private: std::mutex mtx; std::condition_variable cv; int contatore;public: Semaforo(int valore_iniziale) : contatore(valore_iniziale) {}
void wait() { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, [this] { return contatore > 0; }); --contatore; }
void signal() { std::unique_lock<std::mutex> lock(mtx); ++contatore; cv.notify_one(); }};
Semaforo semaforo(1);
void funzione1() { semaforo.wait(); std::cout << "Funzione 1 in esecuzione" << std::endl; std::this_thread::sleep_for(std::chrono::seconds(1)); semaforo.signal();}
void funzione2() { semaforo.wait(); std::cout << "Funzione 2 in esecuzione" << std::endl; std::this_thread::sleep_for(std::chrono::seconds(1)); semaforo.signal();}
int main() { std::thread t1(funzione1); std::thread t2(funzione2);
t1.join(); t2.join();
return 0;}
Esercizio 4
Utilizzare una condition variable per implementare un ciclo produttore-consumatore con più produttori e consumatori.
#include <iostream>#include <queue>#include <thread>#include <mutex>#include <condition_variable>
std::queue<int> coda;std::mutex mtx;std::condition_variable cv;const int MAX_CODA = 10;bool done = false;
void produttore(int id) { for (int i = 0; i < 10; ++i) { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, []{ return coda.size() < MAX_CODA; }); coda.push(i); std::cout << "Produttore " << id << " ha prodotto: " << i << std::endl; cv.notify_all(); }}
void consumatore(int id) { while (true) { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, []{ return !coda.empty() || done; }); if (done && coda.empty()) break; int val = coda.front(); coda.pop(); std::cout << "Consumatore " << id << " ha consumato: " << val << std::endl; cv.notify_all(); }}
int main() { std::thread produttori[3], consumatori[3]; for (int i = 0; i < 3; ++i) { produttori[i] = std::thread(produttore, i+1); consumatori[i] = std::thread(consumatore, i+1); }
for (int i = 0; i < 3; ++i) { produttori[i].join(); }
{ std::unique_lock<std::mutex> lock(mtx); done = true; cv.notify_all(); }
for (int i = 0; i < 3; ++i) { consumatori[i].join(); }
return 0;}
Esercizio 5
Utilizzare una condition variable per implementare un sistema di lettori-scrittori.
#include <iostream>#include <thread>#include <mutex>#include <condition_variable>
std::mutex mtx;std::condition_variable cv;int lettori = 0;bool scrittura_in_corso = false;
void lettore(int id) { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, []{ return !scrittura_in_corso; }); ++lettori; lock.unlock();
std::cout << "Lettore " << id << " sta leggendo." << std::endl; std::this_thread::sleep_for(std::chrono::milliseconds(500));
lock.lock(); --lettori; if (lettori == 0) { cv.notify_all(); } lock.unlock();}
void scrittore(int id) { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, []{ return !scrittura_in_corso && lettori == 0; }); scrittura_in_corso = true; lock.unlock();
std::cout << "Scrittore " << id << " sta scrivendo." << std::endl; std::this_thread::sleep_for(std::chrono::seconds(1));
lock.lock(); scrittura_in_corso = false; cv.notify_all(); lock.unlock();}
int main() { std::thread lettori[3], scrittori[2];
for (int i = 0; i < 3; ++i) { lettori[i] = std::thread(lettore, i+1); } for (int i = 0; i < 2; ++i) { scrittori[i] = std::thread(scrittore, i+1); }
for (int i = 0; i < 3; ++i) { lettori[i].join(); } for (int i = 0; i < 2; ++i) { scrittori[i].join(); }
return 0;}``
`
</div></details>
### Esercizio 6
<details class="mb-10"><summary class="cursor-pointer">Utilizzare una condition variable per sincronizzare l'accesso a un contatore condiviso tra più thread.</summary><div class="py-5">
```cpp#include <iostream>#include <thread>#include <mutex>#include <condition_variable>
int contatore = 0;std::mutex mtx;std::condition_variable cv;
void incrementa(int id) { for (int i = 0; i < 5; ++i) { std::unique_lock<std::mutex> lock(mtx); ++contatore; std::cout << "Thread " << id << " incrementa a " << contatore << std::endl; cv.notify_all(); cv.wait(lock, []{ return contatore % 5 == 0; }); }}
void stampa() { while (true) { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, []{ return contatore % 5 == 0 && contatore > 0; }); std::cout << "Contatore raggiunge multiplo di 5: " << contatore << std::endl; if (contatore >= 20) break; }}
int main() { std::thread t1(incrementa, 1); std::thread t2(incrementa, 2); std::thread t3(stampa);
t1.join(); t2.join(); t3.join();
return 0;}
Esercizio 7
Utilizzare una condition variable per implementare una barriera di sincronizzazione.
#include <iostream>#include <thread>#include <mutex>#include <condition_variable>
const int NUM_THREAD = 5;int count = 0;std::mutex mtx;std::condition_variable cv;
void threadFunzione(int id) { std::cout << "Thread " << id << " pronto\n";
std::unique_lock<std::mutex> lock(mtx); ++count; if (count == NUM_THREAD) { cv.notify_all(); } else { cv.wait(lock, []{ return count == NUM_THREAD; }); }
std::cout << "Thread " << id << " inizia\n";}
int main() { std::thread threads[NUM_THREAD];
for (int i = 0; i < NUM_THREAD; ++i) { threads[i] = std::thread(threadFunzione, i + 1); }
for (int i = 0; i < NUM_THREAD; ++i) { threads[i].join(); }
return 0;}
Esercizio 8
Utilizzare una condition variable per implementare un sistema di lettura e scrittura con priorità ai lettori.
#include <iostream>#include <thread>#include <mutex>#include <condition_variable>
std::mutex mtx;std::condition_variable cv;int lettori = 0;bool scrittura_in_corso = false;
void lettore(int id) { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, []{ return !scrittura_in_corso; }); ++lettori; lock.unlock();
std::cout << "Lettore " << id << " sta leggendo.\n"; std::this_thread::sleep_for(std::chrono::milliseconds(500));
lock.lock(); --lettori; if (lettori == 0) { cv.notify_all(); } lock.unlock();}
void scrittore(int id) { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, []{ return !scrittura_in_corso && lettori == 0; }); scrittura_in_corso = true; lock.unlock();
std::cout << "Scrittore " << id << " sta scrivendo.\n"; std::this_thread::sleep_for(std::chrono::seconds(1));
lock.lock(); scrittura_in_corso = false; cv.notify_all(); lock.unlock();}
int main() { std::thread lettori[3], scrittori[2];
for (int i = 0; i < 3; ++i) { lettori[i] = std::thread(lettore, i+1); } for (int i = 0; i < 2; ++i) { scrittori[i] = std::thread(scrittore, i+1); }
for (int i = 0; i < 3; ++i) { lettori[i].join(); } for (int i = 0; i < 2; ++i) { scrittori[i].join(); }
return 0;}