Sobes.tech
Middle

Hogyan lehet szinkronizálni a szálak közötti interakciót?

sobes.tech MI

Válasz az MI-től

A C/C++-ban több alapvető szinkronizációs mechanizmus létezik:

  • Mutekszok (Mutexek): Biztosítják a kizárólagos hozzáférést a megosztott erőforráshoz. Egy szál, amely megszerzi a mutexet, blokkolja a többi szálat, amíg el nem engedi.

    #include <mutex>
    
    std::mutex my_mutex;
    
    void my_thread_function() {
        my_mutex.lock(); // Mutex megszerzése
        // Munka a megosztott erőforrással
        my_mutex.unlock(); // Mutex elengedése
    }
    

    Vagy RAII-val:

    #include <mutex>
    #include <lock_guard>
    
    std::mutex my_mutex;
    
    void my_thread_function() {
        std::lock_guard<std::mutex> lock(my_mutex); // Mutex megszerzése az objektum létrehozásakor
        // Munka a megosztott erőforrással
        // A mutex automatikusan elengedésre kerül a hatókör végén
    }
    
  • Szelep (Semaphore): A mutexek általánosítása. Számlálót tart fenn, amely lehetővé teszi, hogy egy adott számú szál egyidejűleg hozzáférjen a forráshoz.

    #include <semaphore.h> // POSIX-szelephez
    #include <windows.h> // Windows-szelephez
    
    sem_t my_semaphore; // POSIX-szelep
    
    void my_thread_function() {
        sem_wait(&my_semaphore); // Csökkenti a számlálót, blokkol, ha 0
        // Munka a forrással
        sem_post(&my_semaphore); // Növeli a számlálót
    }
    

    (Megjegyzés: A C++ szabvány nem tartalmaz közvetlenül szelep támogatást, de elérhető rendszerkönyvtárakon vagy harmadik féltől származó implementációkon keresztül.)

  • Feltételes változók (Condition Variables): Olyan mechanizmusok, amelyek lehetővé teszik, hogy egy szál várjon egy adott feltétel bekövetkeztére, miközben felszabadítja a mutexet. Egy másik szál értesítheti a várakozó szálat, hogy a feltétel teljesült.

    #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; }); // Várakozás a feltétel teljesülésére
        // A feltétel teljesült, munka a forrással
    }
    
    void notifying_thread() {
        std::unique_lock<std::mutex> lock(my_mutex);
        condition_met = true;
        lock.unlock(); // A mutex felszabadítása az értesítés előtt (ajánlott)
        my_cv.notify_one(); // Egy várakozó szál értesítése
        // vagy
        // my_cv.notify_all(); // Minden várakozó szál értesítése
    }
    
  • Atomi műveletek (Atomic Operations): Lehetővé teszik egyszerű műveletek végrehajtását változókon (pl. növelés, csökkentés) egyetlen, oszthatatlan műveletként, explicit mutex zárás nélkül.

    #include <atomic>
    
    std::atomic<int> counter(0);
    
    void my_thread_function() {
        counter++; // Atom növelés
        // Vagy:
        // counter.fetch_add(1);
    }
    
  • Olvasási-Írási Lockok (Shared Mutexes): Lehetővé teszik több szálnak az adatok olvasását egyszerre, de csak egy szálnak írhatnak.

    #include <shared_mutex> // C++17 és magasabb
    
    std::shared_mutex my_shared_mutex;
    
    void read_thread() {
        my_shared_mutex.lock_shared(); // Olvasási zárolás
        // Adatok olvasása
        my_shared_mutex.unlock_shared(); // Olvasási zárolás feloldása
    }
    
    void write_thread() {
        my_shared_mutex.lock(); // Írási zárolás (kizárólagos)
        // Adatok írása
        my_shared_mutex.unlock(); // Írási zárolás feloldása
    }
    
  • Barikádok (Barriers): Lehetővé teszik egy csoport szálnak, hogy várjanak, amíg mind el nem érik egy adott pontot a végrehajtásukban, mielőtt folytatnák.

    #include <barrier> // C++20
    
    std::barrier sync_point(4); // Barikád 4 szál számára
    
    void my_thread_function() {
        // Munka a barikád előtt
        sync_point.arrive_and_wait(); // Várakozás, amíg minden szál el nem éri a barikádot
        // Munka a barikád után
    }
    

A konkrét mechanizmus kiválasztása a kölcsönhatás és a megosztott erőforrások jellemzőitől függ.