Sobes.tech
Middle

Hoe kan de interactie tussen threads gesynchroniseerd worden?

sobes.tech AI

Antwoord van AI

Er zijn verschillende belangrijke mechanismen voor synchronisatie en interactie tussen threads in C/C++:

  • Mutexen (Mutual Exclusions): Zorgt voor exclusieve toegang tot een gedeelde bron. Een thread die een mutex heeft vergrendeld, blokkeert andere threads die proberen dezelfde mutex te vergrendelen totdat deze wordt vrijgegeven.

    #include <mutex>
    
    std::mutex my_mutex;
    
    void my_thread_function() {
        my_mutex.lock(); // Mutex vergrendelen
        // Werken met gedeelde bron
        my_mutex.unlock(); // Mutex ontgrendelen
    }
    

    Of met RAII:

    #include <mutex>
    #include <lock_guard>
    
    std::mutex my_mutex;
    
    void my_thread_function() {
        std::lock_guard<std::mutex> lock(my_mutex); // Mutex vergrendelen bij creatie
        // Werken met gedeelde bron
        // Mutex wordt automatisch vrijgegeven bij het verlaten van de scope
    }
    
  • Semaforen (Semaphores): Generalisatie van mutexen. Ondersteunt een teller die bepaalt hoeveel threads gelijktijdig toegang kunnen krijgen tot een bron.

    #include <semaphore.h> // Voor POSIX-semaforen
    #include <windows.h> // Voor Windows-semaforen
    
    sem_t my_semaphore; // POSIX-semafor
    
    void my_thread_function() {
        sem_wait(&my_semaphore); // Teller verlagen, blokkeren als 0
        // Werken met bron
        sem_post(&my_semaphore); // Teller verhogen
    }
    

    (Opmerking: C++ standaard bevat geen semaforen direct, maar ze zijn beschikbaar via systeembibliotheken of third-party implementaties.)

  • Voorwaardelijke variabelen (Condition Variables): Worden gebruikt zodat een thread kan wachten op een bepaalde voorwaarde, terwijl het mutex vrijlaat. Een andere thread kan de wachtende informeren dat de voorwaarde is vervuld.

    #include <mutex>
    #include <condition_variable>
    
    std::mutex my_mutex;
    std::condition_variable my_cv;
    bool condition_met = false;
    
    void waiting_thread() {
        std::unique_lock<std::mutex> lock(my_mutex);
        my_cv.wait(lock, []{ return condition_met; }); // Wacht op vervulling van voorwaarde
        // Voorwaarde vervuld, werken met bron
    }
    
    void notifying_thread() {
        std::unique_lock<std::mutex> lock(my_mutex);
        condition_met = true;
        lock.unlock(); // Vrijlaten van mutex voor notificatie (optioneel, maar aanbevolen)
        my_cv.notify_one(); // Informeer één wachtende thread
        // of
        // my_cv.notify_all(); // Informeer alle wachtende threads
    }
    
  • Atomare operaties (Atomic Operations): Stellen eenvoudige operaties over variabelen in staat (bijvoorbeeld increment, decrement) als één ondeelbare actie, zonder expliciete lock.

    #include <atomic>
    
    std::atomic<int> counter(0);
    
    void my_thread_function() {
        counter++; // Atomair increment
        // Of:
        // counter.fetch_add(1);
    }
    
  • Read-Write Locks (Shared Mutexes): Stellen meerdere threads in staat om gelijktijdig te lezen, maar slechts één om te schrijven.

    #include <shared_mutex> // C++17 en hoger
    
    std::shared_mutex my_shared_mutex;
    
    void read_thread() {
        my_shared_mutex.lock_shared(); // Vergrendelen voor lezen
        // Lezen van data
        my_shared_mutex.unlock_shared(); // Ontgrendelen voor lezen
    }
    
    void write_thread() {
        my_shared_mutex.lock(); // Vergrendelen voor schrijven (exclusief)
        // Schrijven van data
        my_shared_mutex.unlock(); // Ontgrendelen voor schrijven
    }
    
  • Barrières (Barriers): Stellen een groep threads in staat te wachten totdat allen een bepaald punt in hun uitvoering bereiken, voordat ze verder gaan.

    #include <barrier> // C++20
    
    std::barrier sync_point(4); // Barrière voor 4 threads
    
    void my_thread_function() {
        // Werk vóór de barrière
        sync_point.arrive_and_wait(); // Wachten totdat alle threads de barrière bereiken
        // Werk na de barrière
    }
    

De keuze van een specifiek mechanisme hangt af van de aard van de interactie en de gedeelde bronnen.