Sobes.tech
Middle

Kā var sinhronizēt pavedienu mijiedarbību?

sobes.tech AI

Atbilde no AI

Ir daudz galveno mehānismu, kas tiek izmantoti saskarnes sinhronizācijai starp pavedieniem C/C++:

  • Mutexi (Mutexes): Nodrošina ekskluzīvu piekļuvi koplietotajam resursam. Pavediens, kas iegūst mutex, bloķē citus pavedienus, kas mēģina to iegūt, līdz tas tiek atbrīvots.

    #include <mutex>
    
    std::mutex my_mutex;
    
    void my_thread_function() {
        my_mutex.lock(); // Iegūt mutex
        // Darbs ar koplietoto resursu
        my_mutex.unlock(); // Atbrīvot mutex
    }
    

    Vai ar RAII:

    #include <mutex>
    #include <lock_guard>
    
    std::mutex my_mutex;
    
    void my_thread_function() {
        std::lock_guard<std::mutex> lock(my_mutex); // Iegūt mutex, izveidojot objektu
        // Darbs ar koplietoto resursu
        // Mutex automātiski atbrīvojas, izejot no apgabala
    }
    
  • Semafori (Semaphores): Mūsdienu versija mutexiem. Uztur skaitītāju, kas ļauj noteiktam skaitam pavedienu vienlaikus piekļūt resursam.

    #include <semaphore.h> // POSIX semafori
    #include <windows.h> // Windows semafori
    
    sem_t my_semaphore; // POSIX semafors
    
    void my_thread_function() {
        sem_wait(&my_semaphore); // Samazina semafora skaitītāju, bloķē, ja tas ir 0
        // Darbs ar resursu
        sem_post(&my_semaphore); // Palielina semafora skaitītāju
    }
    

    (Piezīme: Standarta C++ tieši neietver semaforus, bet tie ir pieejami caur sistēmas bibliotēkām vai trešo pušu realizācijām)

  • Nosacījuma mainīgie (Condition Variables): Tiek izmantoti, lai pavediens varētu gaidīt noteikta nosacījuma iestāšanos, vienlaikus atbrīvojot mutex. Cits pavediens var paziņot, ka nosacījums ir izpildīts.

    #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; }); // Gaidīt nosacījuma izpildi
        // Nosacījums izpildīts, darbs ar resursu
    }
    
    void notifying_thread() {
        std::unique_lock<std::mutex> lock(my_mutex);
        condition_met = true;
        lock.unlock(); // Atbrīvot mutex pirms paziņojuma (ieteicams)
        my_cv.notify_one(); // Paziņot vienam gaidošajam pavedienam
        // vai
        // my_cv.notify_all(); // Paziņot visiem gaidošajiem pavedieniem
    }
    
  • Atomāras operācijas (Atomic Operations): Ļauj veikt vienkāršas operācijas ar mainīgajiem (piemēram, inkrementu, dekrementu) kā vienotu, nedalāmu darbību, nerequīrējot mutex bloķēšanu.

    #include <atomic>
    
    std::atomic<int> counter(0);
    
    void my_thread_function() {
        counter++; // Atomārs inkrementācija
        // vai:
        // counter.fetch_add(1);
    }
    
  • Lasīšanas un rakstīšanas slēdzenes (Shared Mutexes): Atļauj vairākiem pavedieniem lasīt datus vienlaikus, bet tikai vienam rakstīt.

    #include <shared_mutex> // C++17 un jaunākas versijas
    
    std::shared_mutex my_shared_mutex;
    
    void read_thread() {
        my_shared_mutex.lock_shared(); // Iegūt lasīšanai
        // Lasīt datus
        my_shared_mutex.unlock_shared(); // Atbrīvot lasīšanai
    }
    
    void write_thread() {
        my_shared_mutex.lock(); // Iegūt rakstīšanai (ekskluzīvi)
        // Rakstīt datus
        my_shared_mutex.unlock(); // Atbrīvot rakstīšanai
    }
    
  • Barjeras (Barriers): Atļauj grupai pavedienu gaidīt, līdz visi sasniedz noteiktu punktu savā izpildē, pirms turpināt.

    #include <barrier> // C++20
    
    std::barrier sync_point(4); // Barjera 4 pavedieniem
    
    void my_thread_function() {
        // Darbs pirms barjeras
        sync_point.arrive_and_wait(); // Gaidīt, līdz visi sasniedz barjeru
        // Darbs pēc barjeras
    }
    

Izvēle konkrētam mehānismam ir atkarīga no mijiedarbības rakstura un koplietojamiem resursiem.