Spec-Zone.ru › C++

std::scoped_lock

Определён в заголовке <mutex>
template< class... MutexTypes >
class scoped_lock;
(начиная с C++17)

Класс scoped_lock — это обёртка над мьютексами, предоставляющая удобный механизм в стиле RAII для владения нулём или несколькими мьютексами в течение блока с ограниченной областью видимости.

При создании объекта scoped_lock он пытается получить во владение переданные ему мьютексы. Когда выполнение покидает область видимости, в которой был создан объект scoped_lock, объект scoped_lock уничтожается, а мьютексы освобождаются. Если передано несколько мьютексов, используется алгоритм предотвращения взаимной блокировки, как если бы был вызван std::lock.

Класс scoped_lock нельзя копировать.

Параметры шаблона

MutexTypes - типы мьютексов, которые необходимо заблокировать. Типы должны соответствовать требованиям Lockable, кроме случая sizeof...(MutexTypes) == 1, когда единственный тип должен соответствовать требованиям BasicLockable

Типы-члены

Тип-член Определение
mutex_type
(присутствует при определённых условиях)

Если sizeof...(MutexTypes) == 1, тип-член mutex_type совпадает с Mutex, единственным типом в MutexTypes.... В противном случае члена mutex_type нет.

Функции-члены

(конструктор)
создаёт scoped_lock, при необходимости блокируя переданные мьютексы
(открытая функция-член)
(деструктор)
уничтожает объект scoped_lock, разблокируя лежащие в его основе мьютексы
(открытая функция-член)
operator=
[удалён]
копирующее присваивание не поддерживается
(открытая функция-член)

Примечания

Распространённая ошибка начинающих — «забыть» указать имя переменной scoped_lock, например std::scoped_lock(mtx); (в результате создаётся переменная scoped_lock со значением по умолчанию и именем mtx) или std::scoped_lock{mtx}; (в результате создаётся prvalue-объект, который немедленно уничтожается), из-за чего фактически не создаётся блокировка, удерживающая мьютекс до конца области видимости.

Макрос проверки поддержки Значение Стандарт Возможность
__cpp_lib_scoped_lock 201703L (C++17) std::scoped_lock

Пример

В следующем примере std::scoped_lock используется для блокировки пар мьютексов без взаимной блокировки и в стиле RAII.

#include <chrono>
#include <functional>
#include <iostream>
#include <mutex>
#include <string>
#include <syncstream>
#include <thread>
#include <vector>
using namespace std::chrono_literals;
 
struct Employee
{
    std::vector<std::string> lunch_partners;
    std::string id;
    std::mutex m;
    Employee(std::string id) : id(id) {}
    std::string partners() const
    {
        std::string ret = "Employee " + id + " has lunch partners: ";
        for (int count{}; const auto& partner : lunch_partners)
            ret += (count++ ? ", " : "") + partner;
        return ret;
    }
};
 
void send_mail(Employee&, Employee&)
{
    // Simulate a time-consuming messaging operation
    std::this_thread::sleep_for(1s);
}
 
void assign_lunch_partner(Employee& e1, Employee& e2)
{
    std::osyncstream synced_out(std::cout);
    synced_out << e1.id << " and " << e2.id << " are waiting for locks" << std::endl;

    {
        // Use std::scoped_lock to acquire two locks without worrying about
        // other calls to assign_lunch_partner deadlocking us
        // and it also provides a convenient RAII-style mechanism
        
        std::scoped_lock lock(e1.m, e2.m);

        // Equivalent code 1 (using std::lock and std::lock_guard)
        // std::lock(e1.m, e2.m);
        // std::lock_guard<std::mutex> lk1(e1.m, std::adopt_lock);
        // std::lock_guard<std::mutex> lk2(e2.m, std::adopt_lock);

        // Equivalent code 2 (if unique_locks are needed, e.g. for condition variables)
        // std::unique_lock<std::mutex> lk1(e1.m, std::defer_lock);
        // std::unique_lock<std::mutex> lk2(e2.m, std::defer_lock);
        // std::lock(lk1, lk2);
        synced_out << e1.id << " and " << e2.id << " got locks" << std::endl;
        e1.lunch_partners.push_back(e2.id);
        e2.lunch_partners.push_back(e1.id);
    }
    
    send_mail(e1, e2);
    send_mail(e2, e1);
}
 
int main()
{
    Employee alice("Alice"), bob("Bob"), christina("Christina"), dave("Dave");
 
    // Assign in parallel threads because mailing users about lunch assignments
    // takes a long time
    std::vector<std::thread> threads;
    threads.emplace_back(assign_lunch_partner, std::ref(alice), std::ref(bob));
    threads.emplace_back(assign_lunch_partner, std::ref(christina), std::ref(bob));
    threads.emplace_back(assign_lunch_partner, std::ref(christina), std::ref(alice));
    threads.emplace_back(assign_lunch_partner, std::ref(dave), std::ref(bob));
 
    for (auto& thread : threads)
        thread.join();
    std::osyncstream(std::cout) << alice.partners() << '\n'  
                                << bob.partners() << '\n'
                                << christina.partners() << '\n' 
                                << dave.partners() << '\n';
}

Возможный вывод:

Alice and Bob are waiting for locks
Alice and Bob got locks
Christina and Bob are waiting for locks
Christina and Alice are waiting for locks
Dave and Bob are waiting for locks
Dave and Bob got locks
Christina and Alice got locks
Christina and Bob got locks
Employee Alice has lunch partners: Bob, Christina
Employee Bob has lunch partners: Alice, Dave, Christina
Employee Christina has lunch partners: Alice, Bob
Employee Dave has lunch partners: Bob

Отчёты об ошибках

Следующие отчёты об ошибках, изменяющие поведение, были ретроактивно применены к ранее опубликованным стандартам C++.

Отчёт об ошибке Применён к Опубликованное поведение Исправленное поведение
LWG 2981 C++17 было предоставлено избыточное руководство по выводу типов из scoped_lock<MutexTypes...> удалено

См. также

unique_lock
(C++11)
реализует перемещаемую обёртку владения мьютексом
(шаблон класса)
lock_guard
(C++11)
реализует обёртку владения мьютексом, строго привязанную к области видимости
(шаблон класса)

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

Spec-Zone.ru

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