Namespaces
Variants

std:: shared_mutex

From cppreference.net
Concurrency support library
Threads
(C++11)
(C++20)
this_thread namespace
(C++11)
(C++11)
Cooperative cancellation
Mutual exclusion
(C++11)
shared_mutex
(C++17)
Generic lock management
Condition variables
(C++11)
Semaphores
Latches and Barriers
(C++20)
(C++20)
Futures
(C++11)
(C++11)
(C++11)
Safe reclamation
Hazard pointers
Atomic types
(C++11)
(C++20)
Initialization of atomic types
(C++11) (deprecated in C++20)
(C++11) (deprecated in C++20)
Memory ordering
(C++11) (deprecated in C++26)
Free functions for atomic operations
Free functions for atomic flags
Определено в заголовочном файле <shared_mutex>
class shared_mutex ;
(начиная с C++17)

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

  • shared - несколько потоков могут совместно владеть одним и тем же мьютексом.
  • exclusive - только один поток может владеть мьютексом.

Если один поток получил эксклюзивную блокировку (через lock , try_lock ), никакие другие потоки не могут получить блокировку (включая общую ).

Если один поток получил разделяемую блокировку (через lock_shared , try_lock_shared ), никакой другой поток не может получить эксклюзивную блокировку, но может получить разделяемую блокировку.

Только когда эксклюзивная блокировка не была получена ни одним потоком, общая блокировка может быть получена несколькими потоками.

В одном потоке одновременно может быть захвачена только одна блокировка ( shared или exclusive ).

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

Класс shared_mutex удовлетворяет всем требованиям SharedMutex и StandardLayoutType .

Содержание

Типы членов

Тип члена Определение
native_handle_type ( опционально* ) определяется реализацией

Функции-члены

создает мьютекс
(public member function)
уничтожает мьютекс
(public member function)
operator=
[deleted]
не копируемый
(public member function)
Эксклюзивная блокировка
блокирует мьютекс, ожидает если мьютекс недоступен
(public member function)
пытается заблокировать мьютекс, возвращает управление если мьютекс недоступен
(public member function)
разблокирует мьютекс
(public member function)
Совместная блокировка
блокирует мьютекс для совместного владения, ожидает если мьютекс недоступен
(public member function)
пытается заблокировать мьютекс для совместного владения, возвращает управление если мьютекс недоступен
(public member function)
разблокирует мьютекс (совместное владение)
(public member function)
Нативный дескриптор
возвращает базовый объект нативного дескриптора, определенный реализацией
(public member function)

Пример

Приведённый ниже вывод был сгенерирован на одноядерной машине. Когда thread1 запускается, он входит в цикл в первый раз и вызывает increment() , а затем get() . Однако прежде чем он сможет вывести возвращённое значение в std:: cout , планировщик переводит thread1 в режим ожидания и пробуждает thread2 , который успевает выполнить все три итерации цикла за один раз. Возвращаясь к thread1 , всё ещё находящемуся на первой итерации цикла, он наконец выводит свою локальную копию значения счётчика, которая равна 1 , в std::cout , а затем выполняет оставшиеся две итерации цикла. На многоядерной машине ни один из потоков не переводится в режим ожидания, и вывод с большей вероятностью будет в возрастающем порядке.

#include <iostream>
#include <mutex>
#include <shared_mutex>
#include <syncstream>
#include <thread>
class ThreadSafeCounter
{
public:
    ThreadSafeCounter() = default;
    // Multiple threads/readers can read the counter's value at the same time.
    unsigned int get() const
    {
        std::shared_lock lock(mutex_);
        return value_;
    }
    // Only one thread/writer can increment/write the counter's value.
    void increment()
    {
        std::unique_lock lock(mutex_);
        ++value_;
    }
    // Only one thread/writer can reset/write the counter's value.
    void reset()
    {
        std::unique_lock lock(mutex_);
        value_ = 0;
    }
private:
    mutable std::shared_mutex mutex_;
    unsigned int value_{};
};
int main()
{
    ThreadSafeCounter counter;
    auto increment_and_print = [&counter]()
    {
        for (int i{}; i != 3; ++i)
        {
            counter.increment();
            std::osyncstream(std::cout)
                << std::this_thread::get_id() << ' ' << counter.get() << '\n';
        }
    };
    std::thread thread1(increment_and_print);
    std::thread thread2(increment_and_print);
    thread1.join();
    thread2.join();
}

Возможный вывод:

123084176803584 2
123084176803584 3
123084176803584 4
123084185655040 1
123084185655040 5
123084185655040 6

Смотрите также

предоставляет механизм совместной взаимной блокировки с поддержкой таймаутов
(класс)
реализует перемещаемую обёртку владения совместной блокировкой
(шаблон класса)
реализует перемещаемую обёртку владения блокировкой
(шаблон класса)