Sobes.tech
Middle

Cum se poate sincroniza interacțiunea între fire?

sobes.tech AI

Răspuns de la AI

Există mai multe mecanisme principale de sincronizare a firelor în C++:

  • Mutex-uri: Asigură excluderea mutuală. Doar un fir poate deține un mutex într-un moment dat. Sunt folosite pentru a proteja resursele comune împotriva accesului simultan.

    #include <mutex>
    
    std::mutex myMutex;
    
    void criticalSection() {
        std::lock_guard<std::mutex> lock(myMutex); // Achiziționarea mutex-ului
        // Lucru cu resursa comună
    } // Mutex-ul este eliberat automat la ieșirea din scop
    
  • Semaforuri: Controlează accesul la resurse limitate. Un semafor are un contor care indică numărul de resurse disponibile. Firurile pot diminua (pentru a obține o resursă) sau crește (pentru a elibera).

    #include <semaphore.h> // Folosit de obicei în sistemele POSIX
    
    sem_t mySemaphore;
    
    void initSemaphore(int count) {
        sem_init(&mySemaphore, 0, count); // Inițializare semafor cu contorul count
    }
    
    void acquireResource() {
        sem_wait(&mySemaphore); // Diminuați contorul, blocați dacă este 0
        // Utilizarea resursei
    }
    
    void releaseResource() {
        sem_post(&mySemaphore); // Creșteți contorul
    }
    
  • Variabile de condiție: Permite firelor să aștepte anumite condiții. De obicei sunt folosite împreună cu mutexuri. Un fir care așteaptă eliberează mutex-ul și se blochează până când alt fir îl notifică că condiția a fost îndeplinită.

    #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(); // Notificare unui fir în așteptare
    }
    
    int consumer() {
        std::unique_lock<std::mutex> lock(myMutex);
        myCondition.wait(lock, [&]{ return !myQueue.empty(); }); // Așteptare condiție
        int value = myQueue.front();
        myQueue.pop();
        return value;
    }
    
  • Variabile atomice: Permite efectuarea operațiilor simple (citire, scriere, modificare) în mod atomic, fără a fi nevoie de mutexuri pentru aceste operații.

    #include <atomic>
    
    std::atomic_int atomicCounter(0);
    
    void incrementCounter() {
        atomicCounter++; // Creștere atomică
    }
    
  • Barriere: Sincronizează mai multe fire astfel încât nici unul să nu poată continua până când toți nu au atins bariera.

    #include <barrier> // C++20
    
    std::barrier myBarrier(3); // Barieră pentru 3 fire
    
    void workerThread() {
        // Executarea unei părți a muncii
        myBarrier.arrive_and_wait(); // Așteptarea tuturor firelor la barieră
        // Executarea următoarei părți a muncii
    }
    

Alegerea unui mecanism specific depinde de natura interacțiunii dintre fire:

  • Mutex-uri: Cel mai comun mod de a proteja datele comune.
  • Semaforuri: Gestionarea accesului la resurse limitate.
  • Variabile de condiție: Așteptarea apariției unui eveniment sau stare specifică.
  • Variabile atomice: Executarea eficientă a operațiilor simple și atomice.
  • Barriere: Sincronizarea firelor pentru trecerea comună la etapa următoare.