Spec-Zone.ru › C++

std::shared_mutex

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

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

  • совместный — несколько потоков могут одновременно владеть одним и тем же мьютексом.
  • эксклюзивный — мьютексом может владеть только один поток.

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

Если поток захватил совместную блокировку (с помощью lock_shared, try_lock_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, всё ещё находящемуся на первой итерации цикла, он наконец выводит в std::cout локальную копию значения счётчика — 1, — а затем выполняет оставшиеся две итерации цикла. На многоядерной машине ни один из потоков не приостанавливается, и вывод, скорее всего, будет упорядочен по возрастанию.

#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)
реализует перемещаемую оболочку владения совместным мьютексом
(шаблон класса)
unique_lock
(C++11)
реализует перемещаемую оболочку владения мьютексом
(шаблон класса)

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

Spec-Zone.ru

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