Sobes.tech
Middle

Ako synchronizovať interakciu medzi vláknami?

sobes.tech AI

Odpoveď od AI

Existuje niekoľko hlavných mechanizmov synchronizácie interakcie medzi vláknami v C/C++:

  • Mutexy (Mutually Exclusive Locks): Zabezpečujú exkluzívny prístup ku zdieľanému zdroju. Vlákno, ktoré získalo mutex, blokuje ostatné vlákna, ktoré sa ho snažia získať, až kým mutex neuvoľní.

    #include <mutex>
    
    std::mutex my_mutex;
    
    void my_thread_function() {
        my_mutex.lock(); // Získanie mutexu
        // Práca so zdieľaným zdrojom
        my_mutex.unlock(); // Uvoľnenie mutexu
    }
    

    Alebo s použitím RAII:

    #include <mutex>
    #include <lock_guard>
    
    std::mutex my_mutex;
    
    void my_thread_function() {
        std::lock_guard<std::mutex> lock(my_mutex); // Získanie mutexu pri vytvorení objektu
        // Práca so zdieľaným zdrojom
        // Mutex sa automaticky uvoľní pri opustení rozsahu
    }
    
  • Semafory (Semaphores): Generalizácia mutexov. Podporujú počítadlo, ktoré umožňuje určitý počet vlákien súčasne pristupovať ku zdroju.

    #include <semaphore.h> // Pre POSIX semafory
    #include <windows.h> // Pre Windows semafory
    
    sem_t my_semaphore; // POSIX semafor
    
    void my_thread_function() {
        sem_wait(&my_semaphore); // Znížiť počítadlo semaforu, zablokovať ak je 0
        // Práca so zdrojom
        sem_post(&my_semaphore); // Zvýšiť počítadlo semaforu
    }
    

    (Poznámka: Štandard C++ priamo neobsahuje semafory, ale sú dostupné cez systémové knižnice alebo tretie strany.)

  • Podmienkové premenné (Condition Variables): Používajú sa na to, aby vlákno mohlo čakať na určitú podmienku, pričom uvoľní mutex. Iné vlákno môže oznámiť, že podmienka bola splnená.

    #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; }); // Čakať na splnenie podmienky
        // Podmienka je splnená, práca so zdrojom
    }
    
    void notifying_thread() {
        std::unique_lock<std::mutex> lock(my_mutex);
        condition_met = true;
        lock.unlock(); // Uvoľniť mutex pred oznámením (voliteľné, ale odporúčané)
        my_cv.notify_one(); // Oznámiť jedno čakajúce vlákno
        // alebo
        // my_cv.notify_all(); // Oznámiť všetky čakajúce vlákna
    }
    
  • Atómové operácie (Atomic Operations): Umožňujú vykonávať jednoduché operácie nad premennými (napríklad inkrement, dekrement) ako jednotný, nedeliteľný krok, bez potreby explicitného zámku mutex.

    #include <atomic>
    
    std::atomic<int> counter(0);
    
    void my_thread_function() {
        counter++; // Atómový inkrement
        // Alebo:
        // counter.fetch_add(1);
    }
    
  • Read-Write Locks (Shared Mutexes): Umožňujú viacerým vláknam čítať dáta súčasne, ale len jednému vlákno zapisovať dáta.

    #include <shared_mutex> // C++17 a vyššie
    
    std::shared_mutex my_shared_mutex;
    
    void read_thread() {
        my_shared_mutex.lock_shared(); // Získanie pre čítanie
        // Čítanie dát
        my_shared_mutex.unlock_shared(); // Uvoľnenie pre čítanie
    }
    
    void write_thread() {
        my_shared_mutex.lock(); // Získanie pre zápis (exkluzívne)
        // Zápis dát
        my_shared_mutex.unlock(); // Uvoľnenie pre zápis
    }
    
  • Baréry (Barriers): Umožňujú skupine vlákien čakať, kým všetky nedosiahnu určitý bod vo svojom vykonávaní, predtým než pokračujú.

    #include <barrier> // C++20
    
    std::barrier sync_point(4); // Bariera pre 4 vlákna
    
    void my_thread_function() {
        // Práca pred bariérou
        sync_point.arrive_and_wait(); // Čakanie, kým všetky vlákna nedosiahnu bariéru
        // Práca po bariére
    }
    

Výber konkrétneho mechanizmu závisí od charakteru interakcie a zdieľaných zdrojov.