← Назад ко всем вопросам

Какие знаешь мьютексы

1️⃣ Как кратко ответить

В C++ стандартная библиотека предоставляет несколько типов мьютексов: std::mutex, std::timed_mutex, std::recursive_mutex, std::recursive_timed_mutex, std::shared_mutex и std::shared_timed_mutex. Каждый из них имеет свои особенности и предназначен для различных сценариев синхронизации потоков.

2️⃣ Подробное объяснение темы

Мьютексы (от англ. "mutex" — mutual exclusion) — это механизмы синхронизации, которые используются для предотвращения одновременного доступа нескольких потоков к общим ресурсам. В C++ стандартная библиотека предоставляет несколько типов мьютексов, каждый из которых имеет свои особенности и предназначен для различных сценариев.

  1. std::mutex

    Это базовый тип мьютекса, который предоставляет простейший механизм блокировки. Он используется для защиты критических секций, чтобы только один поток мог выполнять код в этой секции в любой момент времени.

    #include <iostream>
    #include <thread>
    #include <mutex>
    ​
    std::mutex mtx;
    ​
    void print_message(const std::string& message) {
        mtx.lock(); // Блокируем мьютекс
        std::cout << message << std::endl;
        mtx.unlock(); // Разблокируем мьютекс
    }
    ​
    int main() {
        std::thread t1(print_message, "Hello from thread 1");
        std::thread t2(print_message, "Hello from thread 2");
    ​
        t1.join();
        t2.join();
    ​
        return 0;
    }
    

    В этом примере std::mutex используется для синхронизации доступа к std::cout, чтобы избежать одновременного вывода из нескольких потоков.

  2. std::timed_mutex

    Этот мьютекс позволяет задавать время ожидания при попытке захвата блокировки. Если мьютекс не может быть захвачен в течение заданного времени, поток может продолжить выполнение без блокировки.

    #include <iostream>
    #include <thread>
    #include <mutex>
    #include <chrono>
    ​
    std::timed_mutex tmtx;
    ​
    void try_lock_for_example() {
        if (tmtx.try_lock_for(std::chrono::milliseconds(100))) {
            std::cout << "Lock acquired" << std::endl;
            tmtx.unlock();
        } else {
            std::cout << "Lock not acquired" << std::endl;
        }
    }
    ​
    int main() {
        std::thread t1(try_lock_for_example);
        std::thread t2(try_lock_for_example);
    ​
        t1.join();
        t2.join();
    ​
        return 0;
    }
    

    Здесь try_lock_for пытается захватить мьютекс в течение 100 миллисекунд.

  3. std::recursive_mutex

    Этот мьютекс позволяет одному и тому же потоку захватывать мьютекс несколько раз без блокировки. Это полезно в случаях, когда функция вызывает саму себя (рекурсия) и требуется синхронизация.

    #include <iostream>
    #include <thread>
    #include <mutex>
    ​
    std::recursive_mutex rmtx;
    ​
    void recursive_function(int count) {
        if (count <= 0) return;
    ​
        rmtx.lock();
        std::cout << "Recursion level: " << count << std::endl;
        recursive_function(count - 1);
        rmtx.unlock();
    }
    ​
    int main() {
        std::thread t1(recursive_function, 3);
        t1.join();
    ​
        return 0;
    }
    

    В этом примере std::recursive_mutex позволяет функции recursive_function захватывать мьютекс несколько раз.

  4. std::recursive_timed_mutex

    Это комбинация std::recursive_mutex и std::timed_mutex, позволяющая рекурсивное захватывание с возможностью задания времени ожидания.

  5. std::shared_mutex

    Этот мьютекс позволяет нескольким потокам одновременно читать данные, но только одному потоку записывать. Это полезно для сценариев, где чтение данных происходит чаще, чем запись.

    #include <iostream>
    #include <thread>
    #include <shared_mutex>
    ​
    std::shared_mutex smtx;
    int shared_data = 0;
    ​
    void read_data() {
        smtx.lock_shared();
        std::cout << "Read data: " << shared_data << std::endl;
        smtx.unlock_shared();
    }
    ​
    void write_data(int value) {
        smtx.lock();
        shared_data = value;
        std::cout << "Wrote data: " << shared_data << std::endl;
        smtx.unlock();
    }
    ​
    int main() {
        std::thread t1(read_data);
        std::thread t2(write_data, 42);
    ​
        t1.join();
        t2.join();
    ​
        return 0;
    }
    

    В этом примере std::shared_mutex позволяет нескольким потокам одновременно читать shared_data, но только одному потоку записывать.

  6. std::shared_timed_mutex

    Это расширение std::shared_mutex, которое добавляет возможность задания времени ожидания для захвата блокировки.

Каждый из этих мьютексов предоставляет уникальные возможности для управления доступом к ресурсам в многопоточных приложениях. Выбор подходящего мьютекса зависит от конкретных требований к синхронизации в вашем приложении.

Тема: Многопоточность / Синхронизация
Стадия: Tech

🔒 Подпишись на бусти автора и стань Алигатором, чтобы получить полный доступ к функционалу сайта и отслеживать свой прогресс!

Твои заметки