Spec-Zone.ru › C++

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, который немедленно уничтожается), тем самым фактически не создавая блокировку, удерживающую мьютекс до конца области видимости.

std::scoped_lock — альтернатива lock_guard, позволяющая блокировать несколько мьютексов с помощью алгоритма предотвращения взаимной блокировки.

(начиная с 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> удалено

См. также

unique_lock
(C++11)
реализует перемещаемую оболочку владения мьютексом
(шаблон класса)
scoped_lock
(C++17)
оболочка RAII для нескольких мьютексов, предотвращающая взаимную блокировку
(шаблон класса)

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

Spec-Zone.ru

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