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(mtx); (которая по умолчанию создаёт переменную lock_guard с именем mtx) или std::lock_guard{mtx}; (которая создаёт временный объект, который сразу же уничтожается), тем самым не создавая блокировку, удерживающую мьютекс в течение всего срока действия.
|
| (с C++17) |
Пример
Демонстрирует безопасное и небезопасное увеличение целочисленной переменной с помощью двух потоков.
#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/w/cpp/thread/lock_guard