Esercizi Comunicazione tra Thread C++
Codegrind Team•Jul 12 2024
Ecco degli esercizi semplici con soluzione per praticare le basi della comunicazione tra thread in C++.
Esercizio 1
Creare due thread che stampano alternativamente numeri pari e dispari utilizzando mutex per la sincronizzazione.
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx;
bool pariTurno = true;
void stampaPari() {
for (int i = 0; i <= 10; i += 2) {
std::unique_lock<std::mutex> lock(mtx);
while (!pariTurno) {
lock.unlock();
std::this_thread::yield();
lock.lock();
}
std::cout << i << " ";
pariTurno = false;
}
}
void stampaDispari() {
for (int i = 1; i < 10; i += 2) {
std::unique_lock<std::mutex> lock(mtx);
while (pariTurno) {
lock.unlock();
std::this_thread::yield();
lock.lock();
}
std::cout << i << " ";
pariTurno = true;
}
}
int main() {
std::thread t1(stampaPari);
std::thread t2(stampaDispari);
t1.join();
t2.join();
std::cout << std::endl;
return 0;
}
Esercizio 2
Creare un programma che utilizza un condition variable per sincronizzare due thread.
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool pronto = false;
void funzione1() {
std::unique_lock<std::mutex> lock(mtx);
std::cout << "Thread 1 in attesa...\n";
cv.wait(lock, []{ return pronto; });
std::cout << "Thread 1 riprende l'esecuzione.\n";
}
void funzione2() {
std::this_thread::sleep_for(std::chrono::seconds(2));
std::unique_lock<std::mutex> lock(mtx);
pronto = true;
std::cout << "Thread 2 segnala il thread 1.\n";
cv.notify_one();
}
int main() {
std::thread t1(funzione1);
std::thread t2(funzione2);
t1.join();
t2.join();
return 0;
}
Esercizio 3
Creare un programma che utilizza un condition variable per sincronizzare l'accesso a una coda tra un thread produttore e un thread consumatore.
#include <iostream>
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>
std::queue<int> coda;
std::mutex mtx;
std::condition_variable cv;
bool done = false;
void produttore() {
for (int i = 0; i < 10; ++i) {
std::unique_lock<std::mutex> lock(mtx);
coda.push(i);
std::cout << "Prodotto: " << i << std::endl;
cv.notify_one();
}
std::unique_lock<std::mutex> lock(mtx);
done = true;
cv.notify_one();
}
void consumatore() {
while (true) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return !coda.empty() || done; });
while (!coda.empty()) {
int val = coda.front();
coda.pop();
std::cout << "Consumato: " << val << std::endl;
}
if (done && coda.empty()) break;
}
}
int main() {
std::thread t1(produttore);
std::thread t2(consumatore);
t1.join();
t2.join();
return 0;
}
Esercizio 4
Creare un programma che utilizza un atomic bool per controllare la terminazione di un thread da un altro thread.
#include <iostream>
#include <thread>
#include <atomic>
std::atomic<bool> running(true);
void funzione() {
while (running) {
std::cout << "Thread in esecuzione...\n";
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
std::cout << "Thread terminato.\n";
}
int main() {
std::thread t(funzione);
std::this_thread::sleep_for(std::chrono::seconds(3));
running = false;
t.join();
return 0;
}
Esercizio 5
Creare un programma che utilizza un future per ottenere il risultato di un calcolo effettuato in un thread separato.
#include <iostream>
#include <thread>
#include <future>
int calcolo(int x) {
std::this_thread::sleep_for(std::chrono::seconds(2));
return x * x;
}
int main() {
std::future<int> risultato = std::async(std::launch::async, calcolo, 5);
std::cout << "In attesa del risultato...\n";
std::cout << "Risultato: " << risultato.get() << std::endl;
return 0;
}
Esercizio 6
Creare un programma che utilizza un promise per inviare il risultato di un calcolo da un thread a un altro.
#include <iostream>
#include <thread>
#include <future>
void calcolo(std::promise<int>&& prom, int x) {
std::this_thread::sleep_for(std::chrono::seconds(2));
prom.set_value(x * x);
}
int main() {
std::promise<int> prom;
std::future<int> fut = prom.get_future();
std::thread t(calcolo, std::move(prom), 5);
std::cout << "In attesa del risultato...\n";
std::cout << "Risultato: " << fut.get() << std::endl;
t.join();
return 0;
}
Esercizio 7
Creare un programma che utilizza un barrier per sincronizzare l'inizio di più thread.
#include <iostream>
#include <thread>
#include <barrier>
std::barrier barriera(3);
void funzione(int id) {
std::cout << "Thread " << id << " pronto\n";
barriera.arrive_and_wait();
std::cout << "Thread " << id << " in esecuzione\n";
}
int main() {
std::thread t1(funzione, 1);
std::thread t2(funzione, 2);
std::thread t3(funzione, 3);
t1.join();
t2.join();
t3.join();
return 0;
}
Esercizio 8
Creare un programma che utilizza un latch per aspettare la fine dell'esecuzione di più thread.
#include <iostream>
#include <thread>
#include <latch>
std::latch latch(3);
void funzione(int id) {
std::cout << "Thread " << id << " inizia\n";
std::this_thread::sleep_for(std::chrono::seconds(id));
std::cout << "Thread " << id << " termina\n";
latch.count_down();
}
int main() {
std::thread t1(funzione, 1);
std::thread t2(funzione, 2);
std::thread t3(funzione, 3);
latch.wait();
std::cout << "Tutti i thread sono terminati\n";
t1.join();
t2.join();
t3.join();
return 0;
}