Sobes.tech
Middle

Jak lze synchronizovat interakci mezi vlákny?

sobes.tech AI

Odpověď od AI

Existuje několik hlavních mechanismů synchronizace a interakce mezi vlákny v C/C++:

  • Mutexy (Mutually Exclusive Locks): Zajišťují exkluzivní přístup ke sdílenému zdroji. Vlákno, které mutex uzamkne, blokuje ostatní vlákna, dokud mutex neuvolní.

    #include <mutex>
    
    std::mutex my_mutex;
    
    void my_thread_function() {
        my_mutex.lock(); // Uzamčení mutexu
        // Práce se sdíleným zdrojem
        my_mutex.unlock(); // Odemykání mutexu
    }
    

    Nebo s RAII:

    #include <mutex>
    #include <lock_guard>
    
    std::mutex my_mutex;
    
    void my_thread_function() {
        std::lock_guard<std::mutex> lock(my_mutex); // Uzamčení mutexu při vytvoření objektu
        // Práce se sdíleným zdrojem
        // Mutex bude automaticky odemčen při opuštění rozsahu
    }
    
  • Semafory (Semaphores): Obecnější než mutexy. Udržují čítač, který umožňuje určitý počet vláken současně přistupovat ke zdroji.

    #include <semaphore.h> // Pro POSIX semafory
    #include <windows.h> // Pro Windows semafory
    
    sem_t my_semaphore; // POSIX semafor
    
    void my_thread_function() {
        sem_wait(&my_semaphore); // Snížení čítače semaforu, zablokování pokud je 0
        // Práce se zdrojem
        sem_post(&my_semaphore); // Zvýšení čítače semaforu
    }
    

    (Poznámka: Standard C++ přímo neobsahuje semafory, ale jsou dostupné přes systémové knihovny nebo třetí strany.)

  • Podmíněné proměnné (Condition Variables): Umožňují vláknu čekat na určitý stav, přičemž uvolní mutex. Jiná vlákna mohou oznámit, že podmínka je splněna.

    #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; }); // Čekání na splnění podmínky
        // Podmínka splněna, práce se zdrojem
    }
    
    void notifying_thread() {
        std::unique_lock<std::mutex> lock(my_mutex);
        condition_met = true;
        lock.unlock(); // Uvolnění mutexu před oznámením (volitelné, ale doporučené)
        my_cv.notify_one(); // Oznámení jednomu čekajícímu vláknu
        // nebo
        // my_cv.notify_all(); // Oznámení všem čekajícím vláknům
    }
    
  • Atomické operace (Atomic Operations): Umožňují provádět jednoduché operace nad proměnnými (například inkrementace, dekrementace) jako nedělitelnou akci bez nutnosti explicitního zamykání mutexu.

    #include <atomic>
    
    std::atomic<int> counter(0);
    
    void my_thread_function() {
        counter++; // Atomická inkrementace
        // Nebo:
        // counter.fetch_add(1);
    }
    
  • Sdílené zámky (Shared Mutexes): Umožňují více vláknům číst data současně, ale pouze jednomu zapisovat.

    #include <shared_mutex> // C++17 a vyšší
    
    std::shared_mutex my_shared_mutex;
    
    void read_thread() {
        my_shared_mutex.lock_shared(); // Zamknout pro čtení
        // Čtení dat
        my_shared_mutex.unlock_shared(); // Odemknout pro čtení
    }
    
    void write_thread() {
        my_shared_mutex.lock(); // Zamknout pro zápis (exkluzivní)
        // Zápis dat
        my_shared_mutex.unlock(); // Odemknout pro zápis
    }
    
  • Barriéry (Barriers): Umožňují skupině vláken čekat, dokud všechna nedosáhnou určitého bodu ve své vykonávací sekvenci, před pokračováním.

    #include <barrier> // C++20
    
    std::barrier sync_point(4); // Barikáda pro 4 vlákna
    
    void my_thread_function() {
        // Práce před bariérou
        sync_point.arrive_and_wait(); // Čekání, dokud všechna vlákna nedosáhnou bariéry
        // Práce po bariéře
    }
    

Volba konkrétního mechanismu závisí na povaze interakce a sdílených zdrojů.