Sobes.tech
Middle

Kuidas saab niitide vahelist suhtlust sünkroniseerida?

sobes.tech AI

Vastus AI-lt

On olemas mitu peamist mehhanismi, mis kasutavad sünkroniseerimiseks lõimede vahel C/C++:

  • Mutexid (Mutexes): Tagavad eksklusiivse juurdepääsu jagatud ressursile. Lõim, mis omandab mutexi, blokeerib teised lõimed, kes püüavad seda omandada, kuni mutex vabastatakse.

    #include <mutex>
    
    std::mutex my_mutex;
    
    void my_thread_function() {
        my_mutex.lock(); // Mutexi omandamine
        // Töö jagatud ressursiga
        my_mutex.unlock(); // Mutexi vabastamine
    }
    

    Või RAII kasutades:

    #include <mutex>
    #include <lock_guard>
    
    std::mutex my_mutex;
    
    void my_thread_function() {
        std::lock_guard<std::mutex> lock(my_mutex); // Mutexi omandamine objekti loomisel
        // Töö jagatud ressursiga
        // Mutex vabastatakse automaatselt väljapääsuga ulatusest
    }
    
  • Semaforid (Semaphores): Mütakse laienemine. Hoiab arvestit, mis võimaldab teatud arvul lõimedel samaaegselt juurdepääsu ressursile.

    #include <semaphore.h> // POSIX semaforid
    #include <windows.h> // Windows semaforid
    
    sem_t my_semaphore; // POSIX semafor
    
    void my_thread_function() {
        sem_wait(&my_semaphore); // Vähendab semafori arvestit, blokeerib kui 0
        // Töö ressursiga
        sem_post(&my_semaphore); // Suurendab semafori arvestit
    }
    

    (Märkus: Standard C++ ei sisalda semaforeid otse, kuid need on saadaval süsteemiraamatukogude või kolmanda osapoole teostuste kaudu)

  • Tingimusmuutujad (Condition Variables): Kasutatakse selleks, et lõim saaks oodata teatud tingimuse täitumist, vabastades samal ajal mutexi. Teine lõim võib teavitada ootavat, et tingimus on täidetud.

    #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; }); // Oodata tingimuse täitumist
        // Tingimus täidetud, töö ressursiga
    }
    
    void notifying_thread() {
        std::unique_lock<std::mutex> lock(my_mutex);
        condition_met = true;
        lock.unlock(); // Vabastada mutex enne teavitamist (valikuline, kuid soovitatav)
        my_cv.notify_one(); // Teavitada ühte ootavat lõime
        // või
        // my_cv.notify_all(); // Teavitada kõiki ootavaid lõime
    }
    
  • Atomaarsed operatsioonid (Atomic Operations): Annab võimaluse teha lihtsaid operatsioone muutujate üle (näiteks, suurendamine, vähendamine) ühe tervikliku, jagamatuna toiminguna, ilma mutexi otsese lukustamiseta.

    #include <atomic>
    
    std::atomic<int> counter(0);
    
    void my_thread_function() {
        counter++; // Atomaarselt suurendamine
        // Või:
        // counter.fetch_add(1);
    }
    
  • Lugemis- ja kirjutuslukk (Shared Mutex): Annab mitmele lõimile võimaluse samaaegselt lugeda andmeid, kuid ainult ühele kirjutada.

    #include <shared_mutex> // C++17 ja uuemad
    
    std::shared_mutex my_shared_mutex;
    
    void read_thread() {
        my_shared_mutex.lock_shared(); // Lukustada lugemiseks
        // Andmete lugemine
        my_shared_mutex.unlock_shared(); // Vabastada lugemiseks
    }
    
    void write_thread() {
        my_shared_mutex.lock(); // Lukustada kirjutamiseks (eksklusiivne)
        // Andmete kirjutamine
        my_shared_mutex.unlock(); // Vabastada kirjutamiseks
    }
    
  • Barjäärid (Barriers): Annab grupile lõimidele võimaluse oodata, kuni kõik jõuavad teatud punkti oma täitmises, enne kui jätkata.

    #include <barrier> // C++20
    
    std::barrier sync_point(4); // Barjäär 4 lõimale
    
    void my_thread_function() {
        // Enne barjääri tehtav töö
        sync_point.arrive_and_wait(); // Oodata, kuni kõik jõuavad barjääri
        // Pärast barjääri tehtav töö
    }
    

Valik konkreetse mehhanismi vahel sõltub suhtluse iseloomust ja jagatud ressurssidest.