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=
[удалён] | копирующее присваивание не поддерживается (открытая функция-член) |
Эксклюзивная блокировка |
|
| блокирует мьютекс; ожидает, если мьютекс недоступен (открытая функция-член) |
|
| пытается заблокировать мьютекс и возвращает управление, если мьютекс недоступен (открытая функция-член) |
|
| разблокирует мьютекс (открытая функция-член) |
|
Совместная блокировка |
|
| блокирует мьютекс для совместного владения; ожидает, если мьютекс недоступен (открытая функция-член) |
|
| пытается заблокировать мьютекс для совместного владения и возвращает управление, если мьютекс недоступен (открытая функция-член) |
|
| разблокирует мьютекс (совместное владение) (открытая функция-член) |
|
Нативный дескриптор |
|
| возвращает нативный объект-дескриптор, определяемый реализацией (открытая функция-член) |
|
Пример
Приведённый ниже вывод был получен на одноядерной машине. Когда 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
См. также
|
(C++14) | предоставляет механизм совместного взаимоисключения и реализует блокировку с тайм-аутом (класс) |
|
(C++14) | реализует перемещаемую оболочку владения совместным мьютексом (шаблон класса) |
|
(C++11) | реализует перемещаемую оболочку владения мьютексом (шаблон класса) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/thread/shared_mutex