🚀 Nuova versione beta disponibile! Feedback o problemi? Contattaci

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;
}