Spec-Zone.ru › C++

std::shared_mutex

Определено в заголовочном файле <shared_mutex>
class shared_mutex;
(с C++17)

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

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

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

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

Только когда блокировка exclusive не приобретена ни одним потоком, блокировку shared могут приобрести несколько потоков.

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

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

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

Типы членов

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

Члены-функции

(конструктор)
конструирует мьютекс
(публичный член-функция)
(деструктор)
уничтожает мьютекс
(публичный член-функция)
operator=
[удалено]
не допускает копирования
(публичный член-функция)
Эксклюзивная блокировка
lock
блокирует мьютекс, ожидает, если мьютекс недоступен
(публичный член-функция)
try_lock
пытается заблокировать мьютекс, возвращает результат, если мьютекс недоступен
(публичный член-функция)
unlock
разблокирует мьютекс
(публичный член-функция)
Разделяемая блокировка
lock_shared
блокирует мьютекс для совместного владения, ожидает, если мьютекс недоступен
(публичный член-функция)
try_lock_shared
пытается заблокировать мьютекс для совместного владения, возвращает результат, если мьютекс недоступен
(публичный член-функция)
unlock_shared
разблокирует мьютекс (совместное владение)
(публичный член-функция)
Нативный обработчик
native_handle
возвращает объект нативного обработчика (определяется реализацией)
(публичный член-функция)

Пример

Вывод ниже был сгенерирован на одноядерной машине. Когда 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

См. также

shared_timed_mutex
(C++14)
предоставляет механизм совместного взаимного исключения и реализует блокировку с таймаутом
(класс)
shared_lock
(C++14)
реализует перемещаемую оболочку для shared mutex'а
(шаблон класса)
unique_lock
(C++11)
реализует перемещаемую оболочку для mutex'а
(шаблон класса)

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/thread/shared_mutex

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API