Sobes.tech
Middle

Kako sinhronizovati interakciju između niti?

sobes.tech АИ

Одговор од АИ

Postoji nekoliko osnovnih mehanizama za sinhronizaciju niti u C++:

  • Muteksi (Mutexi): Osiguravaju međusobno isključivanje. Samo jedna nit može imati muteks u bilo kom trenutku. Koriste se za zaštitu zajedničkih resursa od istovremenog pristupa.

    #include <mutex>
    
    std::mutex myMutex;
    
    void criticalSection() {
        std::lock_guard<std::mutex> lock(myMutex); // Zauzimanje muteksa
        // Rad sa zajedničkim resursom
    } // Muteks se automatski oslobađa pri izlasku iz opsega
    
  • Semafori: Upravljaju pristupom ograničenom broju resursa. Semafor ima brojač koji ukazuje na broj dostupnih resursa. Niti smanjuju (za dobijanje resursa) i povećavaju (za oslobađanje resursa) taj brojač.

    #include <semaphore.h> // Obično se koristi u POSIX sistemima
    
    sem_t mySemaphore;
    
    void initSemaphore(int count) {
        sem_init(&mySemaphore, 0, count); // Inicijalizacija semafora sa brojačem count
    }
    
    void acquireResource() {
        sem_wait(&mySemaphore); // Smanjenje brojača, blokira ako je 0
        // Korišćenje resursa
    }
    
    void releaseResource() {
        sem_post(&mySemaphore); // Povećanje brojača
    }
    
  • Uslovne promenljive: Omogućavaju nitima da čekaju određeni uslov. Obično se koriste zajedno sa muteksima. Nit koja čeka uslov oslobađa muteks i blokira se dok je ne obavesti druga nit da je uslov ispunjen.

    #include <condition_variable>
    #include <mutex>
    #include <queue>
    
    std::condition_variable myCondition;
    std::mutex myMutex;
    std::queue<int> myQueue;
    
    void producer(int value) {
        std::lock_guard<std::mutex> lock(myMutex);
        myQueue.push(value);
        myCondition.notify_one(); // Obaveštavanje jedne čekajuće niti
    }
    
    int consumer() {
        std::unique_lock<std::mutex> lock(myMutex);
        myCondition.wait(lock, [&]{ return !myQueue.empty(); }); // Čekanje uslova
        int value = myQueue.front();
        myQueue.pop();
        return value;
    }
    
  • Atomarne promenljive: Omogućavaju izvršavanje jednostavnih operacija (čitanje, pisanje, modifikacija) atomskim putem, bez potrebe za korišćenjem muteksa za te operacije.

    #include <atomic>
    
    std::atomic_int atomicCounter(0);
    
    void incrementCounter() {
        atomicCounter++; // Atomicko povećanje
    }
    
  • Barijere: Sinhronizuju više niti tako da nijedna ne može nastaviti izvršavanje dok sve ne dostignu barijeru.

    #include <barrier> // C++20
    
    std::barrier myBarrier(3); // Barijera za 3 niti
    
    void workerThread() {
        // Izvršavanje dela posla
        myBarrier.arrive_and_wait(); // Čekanje svih niti na barijeri
        // Izvršavanje sledećeg dela posla
    }
    

Izbor određenog mehanizma zavisi od karaktera interakcije između niti:

  • Muteksi: Najčešći način zaštite zajedničkih podataka.
  • Semafori: Upravljanje pristupom ograničenom broju resursa.
  • Uslovne promenljive: Čekanje niti na određeni događaj ili stanje.
  • Atomarne promenljive: Efikasno izvršavanje jednostavnih, atomskih operacija.
  • Barijere: Sinhronizacija niti za zajednički prelaz na sledeći korak.