Sobes.tech
Middle

Ինչպե՞ս կարելի է սինխրոնիզացնել թելերի միջև փոխազդեցությունը։

sobes.tech AI

Պատասխան AI-ից

Կան մի քանի հիմնական մեխանիզմներ՝ սինխրոնիզացիայի համար C/C++-ում՝

  • Մյուտեքսներ (Mutexes): ապահովում են բացառիկ մուտք դեպի բաժանվող ռեսուրս։ Վերցնող թելը, որը գրավում է մյուտեքսը, խոչընդոտում է մյուս թելերին, որոնք փորձում են այն գրավել, մինչև որ այն ազատվի։

    #include <mutex>
    
    std::mutex my_mutex;
    
    void my_thread_function() {
        my_mutex.lock(); // Գրավում է մյուտեքսը
        // Աշխատանք բաժանվող ռեսուրսի հետ
        my_mutex.unlock(); // Անցկացնում է մյուտեքսը
    }
    

    Կամ RAII-ով՝

    #include <mutex>
    #include <lock_guard>
    
    std::mutex my_mutex;
    
    void my_thread_function() {
        std::lock_guard<std::mutex> lock(my_mutex); // Գրավում է մյուտեքսը օբյեկտի ստեղծման ժամանակ
        // Աշխատանք բաժանվող ռեսուրսի հետ
        // Մյուտեքսը ավտոմատ կերպով ազատվում է, երբ դուրս է գալիս տեսադաշտից
    }
    
  • Սեմաֆորներ (Semaphores): Մյուտեքսների ընդհանրացում։ Պահպանում է հաշվիչ, որը թույլ է տալիս որոշակի քանակությամբ թելերի միաժամանակ մուտք ունենալ ռեսուրս։

    #include <semaphore.h> // POSIX սեմաֆորների համար
    #include <windows.h> // Windows սեմաֆորների համար
    
    sem_t my_semaphore; // POSIX սեմաֆոր
    
    void my_thread_function() {
        sem_wait(&my_semaphore); // Հետեւել է սեմաֆորի հաշվիչը, արգելափակել եթե 0
        // Աշխատանք ռեսուրսի հետ
        sem_post(&my_semaphore); // Ավելացնել սեմաֆորի հաշվիչը
    }
    

    (Նշում՝ Ստանդարտ C++-ը չի ներառում սեմաֆորներ ուղղակի, բայց դրանք հասանելի են համակարգային գրադարանների կամ երրորդ կողմի իրականացման միջոցով)

  • Կոնդիցիոն փոփոխականներ (Condition Variables): Օգտագործվում են այն նպատակով, որ թելն սպասի որոշակի պայմանի կատարմանը, միաժամանակ ազատելով մյուտեքսը։ Մյուս թելը կարող է տեղեկացնել սպասողին, որ պայմանը կատարվել է։

    #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; }); // Սպասել պայմանի կատարմանը
        // Պայմանն իրականացվել է, աշխատել ռեսուրսի հետ
    }
    
    void notifying_thread() {
        std::unique_lock<std::mutex> lock(my_mutex);
        condition_met = true;
        lock.unlock(); // Անցկացնել մյուտեքսը նախքան տեղեկացնելը (ընտրովի, բայց խորհուրդ է տրվում)
        my_cv.notify_one(); // Տեղեկացնել մեկ սպասող թելին
        // կամ
        // my_cv.notify_all(); // Տեղեկացնել բոլոր սպասող թելերին
    }
    
  • Ատոմարային օպերացիաներ (Atomic Operations): Позволяют выполнять простые операции над переменными (например, инкремент, декремент) как единое, неделимое действие, не требующее явной блокировки мютекс։

    #include <atomic>
    
    std::atomic<int> counter(0);
    
    void my_thread_function() {
        counter++; // Ատոմարային ինկրեմենտ
        // կամ:
        // counter.fetch_add(1);
    }
    
  • Կարդալ-գրել լոկերներ (Shared Mutexes): Позволяют нескольким потокам читать данные одновременно, но только одному потоку писать данные.

    #include <shared_mutex> // C++17 և բարձր
    
    std::shared_mutex my_shared_mutex;
    
    void read_thread() {
        my_shared_mutex.lock_shared(); // Գրավում է ընթերցման համար
        // Ավելին՝ ընթերցում տվյալները
        my_shared_mutex.unlock_shared(); // Անցկացնել ընթերցման համար
    }
    
    void write_thread() {
        my_shared_mutex.lock(); // Գրավում է գրելու համար (էքսկլյուզիվ)
        // Գրանցում տվյալները
        my_shared_mutex.unlock(); // Անցկացնել գրելու համար
    }
    
  • Բարեր (Barriers): Позволяют группе потоков ожидать, пока все достигнут определенной точки в своем выполнении, прежде чем продолжить.

    #include <barrier> // C++20
    
    std::barrier sync_point(4); // Բարьер 4 թելերի համար
    
    void my_thread_function() {
        // Աշխատանք առաջ բարիեր
        sync_point.arrive_and_wait(); // Սպասել, մինչև բոլոր թելերը հասնեն բարիերին
        // Աշխատանք բարիերից հետո
    }
    

Ընտրությունը կոնկրետ մեխանիզմի կախված է փոխազդեցության բնույթից և բաժանվող ռեսուրսներից։