std::lock_guard
Определён в заголовочном файле <mutex> | ||
|---|---|---|
template< class Mutex > class lock_guard; | (начиная с C++11) |
Класс lock_guard — это оболочка для мьютекса, предоставляющая удобный механизм в стиле RAII для владения мьютексом в течение времени жизни блока области видимости.
При создании объекта lock_guard он пытается получить владение переданным ему мьютексом. Когда выполнение покидает область видимости, в которой был создан объект lock_guard, объект lock_guard уничтожается, и мьютекс освобождается.
Класс lock_guard нельзя копировать.
Параметры шаблона
| Mutex | - | тип мьютекса, который нужно заблокировать. Тип должен соответствовать требованиям BasicLockable |
Типы-члены
| Тип-член | Определение |
|---|---|
mutex_type | Mutex |
Функции-члены
создаёт lock_guard, при необходимости блокируя переданный мьютекс (открытая функция-член) |
|
уничтожает объект lock_guard и разблокирует базовый мьютекс (открытая функция-член) |
|
|
operator=
[удалён] | копирующее присваивание не поддерживается (открытая функция-член) |
Примечания
Распространённая ошибка начинающих — «забыть» указать имя переменной типа lock_guard, например std::lock_guard<std::mutex>(mtx); (что выполняет конструирование по умолчанию переменной типа lock_guard с именем mtx) или std::lock_guard{mtx}; (что создаёт объект prvalue, который немедленно уничтожается), тем самым фактически не создавая блокировку, удерживающую мьютекс до конца области видимости.
|
| (начиная с C++17) |
Пример
Демонстрация безопасного и небезопасного увеличения значения volatile-переменной двумя потоками.
#include <iostream>
#include <mutex>
#include <string_view>
#include <syncstream>
#include <thread>
volatile int g_i = 0;
std::mutex g_i_mutex; // protects g_i
void safe_increment(int iterations)
{
const std::lock_guard<std::mutex> lock(g_i_mutex);
while (iterations-- > 0)
g_i = g_i + 1;
std::cout << "thread #" << std::this_thread::get_id() << ", g_i: " << g_i << '\n';
// g_i_mutex is automatically released when lock goes out of scope
}
void unsafe_increment(int iterations)
{
while (iterations-- > 0)
g_i = g_i + 1;
std::osyncstream(std::cout) << "thread #" << std::this_thread::get_id()
<< ", g_i: " << g_i << '\n';
}
int main()
{
auto test = [](std::string_view fun_name, auto fun)
{
g_i = 0;
std::cout << fun_name << ":\nbefore, g_i: " << g_i << '\n';
{
std::jthread t1(fun, 1'000'000);
std::jthread t2(fun, 1'000'000);
}
std::cout << "after, g_i: " << g_i << "\n\n";
};
test("safe_increment", safe_increment);
test("unsafe_increment", unsafe_increment);
}
Возможный вывод:
safe_increment: before, g_i: 0 thread #140121493231360, g_i: 1000000 thread #140121484838656, g_i: 2000000 after, g_i: 2000000 unsafe_increment: before, g_i: 0 thread #140121484838656, g_i: 1028945 thread #140121493231360, g_i: 1034337 after, g_i: 1034337
Отчёты об ошибках
Следующие отчёты об ошибках, меняющие поведение, были применены задним числом к ранее опубликованным стандартам C++.
| DR | Применён к | Опубликованное поведение | Корректное поведение |
|---|---|---|---|
| LWG 2981 | C++17 | предоставлялось избыточное руководство по выводу типов для lock_guard<Mutex> | удалено |
См. также
|
(C++11) | реализует перемещаемую оболочку владения мьютексом (шаблон класса) |
|
(C++17) | оболочка RAII для нескольких мьютексов, предотвращающая взаимную блокировку (шаблон класса) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/thread/lock_guard