Namespaces
Variants

std:: lock

From cppreference.net
Concurrency support library
Threads
(C++11)
(C++20)
this_thread namespace
(C++11)
(C++11)
Cooperative cancellation
Mutual exclusion
Generic lock management
lock
(C++11)
(C++11)
(C++11)
(C++11)
Condition variables
(C++11)
Semaphores
Latches and Barriers
(C++20)
(C++20)
Futures
(C++11)
(C++11)
(C++11)
Safe reclamation
Hazard pointers
Atomic types
(C++11)
(C++20)
Initialization of atomic types
(C++11) (deprecated in C++20)
(C++11) (deprecated in C++20)
Memory ordering
(C++11) (deprecated in C++26)
Free functions for atomic operations
Free functions for atomic flags
Определено в заголовке <mutex>
template < class Lockable1, class Lockable2, class ... LockableN >
void lock ( Lockable1 & lock1, Lockable2 & lock2, LockableN & ... lockn ) ;
(начиная с C++11)

Блокирует данные Lockable объекты lock1 , lock2 , ... , lockn используя алгоритм предотвращения взаимоблокировок для избежания deadlock.

Объекты блокируются с помощью неуказанной последовательности вызовов lock , try_lock и unlock . Если вызов lock или unlock приводит к исключению, unlock вызывается для всех заблокированных объектов перед повторным выбросом исключения.

Содержание

Параметры

lock1, lock2, ... , lockn - объекты Lockable для блокировки

Возвращаемое значение

(нет)

Примечания

Boost предоставляет версию этой функции которая принимает последовательность Lockable объектов, определенную парой итераторов.

std::scoped_lock предоставляет RAII обёртку для этой функции и обычно предпочтительнее прямого вызова std::lock .

Пример

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

#include <chrono>
#include <functional>
#include <iostream>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
struct Employee
{
    Employee(std::string id) : id(id) {}
    std::string id;
    std::vector<std::string> lunch_partners;
    std::mutex m;
    std::string output() const
    {
        std::string ret = "Сотрудник " + id + " имеет партнеров по обеду: ";
        for (auto n{lunch_partners.size()}; const auto& partner : lunch_partners)
            ret += partner + (--n ? ", " : "");
        return ret;
    }
};
void send_mail(Employee&, Employee&)
{
    // Имитация трудоемкой операции обмена сообщениями
    std::this_thread::sleep_for(std::chrono::milliseconds(696));
}
void assign_lunch_partner(Employee& e1, Employee& e2)
{
    static std::mutex io_mutex;
    {
        std::lock_guard<std::mutex> lk(io_mutex);
        std::cout << e1.id << " и " << e2.id << " ожидают блокировок" << std::endl;
    }
    // Используйте std::lock для получения двух блокировок без опасений о 
    // другие вызовы assign_lunch_partrier блокируют нас
    {
        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);
    // Эквивалентный код (если требуются unique_lock, например, для переменных условий)
    //  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);
    // Superior solution available in C++17
    //  std::scoped_lock lk(e1.m, e2.m);
        {
            std::lock_guard<std::mutex> lk(io_mutex);
            std::cout << e1.id << " и " << e2.id << " получил блокировки" << std::endl;
        }
        e1.партнеры по обеду.push_back(e2.id);
        e2.партнеры_по_обеду.push_back(e1.id);
    }
    send_mail(e1, e2);
    send_mail(e2, e1);
}
int main()
{
    Employee alice("Алиса"), bob("Боб"), christina("Кристина"), dave("Дейв");
    // Назначение в параллельных потоках, так как пользователям рассылаются уведомления о назначениях на обед
    // занимает много времени
    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::cout << alice.вывод() << '\n'
              << bob.вывод() << '\n'
              << christina.вывод() << '\n'
              << dave.вывод() << '\n';
}

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

Алиса и Боб ждут блокировок
Алиса и Боб получили блокировки
Кристина и Боб ждут блокировок
Кристина и Боб получили блокировки
Кристина и Алиса ждут блокировок
Дэйв и Боб ждут блокировок
Дэйв и Боб получили блокировки
Кристина и Алиса получили блокировки
Сотрудник Алиса имеет партнеров по обеду: Боб, Кристина
Сотрудник Боб имеет партнеров по обеду: Алиса, Кристина, Дэйв
Сотрудник Кристина имеет партнеров по обеду: Боб, Алиса
Сотрудник Дэйв имеет партнеров по обеду: Боб

Смотрите также

реализует перемещаемую обёртку владения мьютексом
(шаблон класса)
(C++11)
пытается получить владение мьютексами с помощью повторных вызовов try_lock
(шаблон функции)
RAII-обёртка для нескольких мьютексов, избегающая взаимоблокировок
(шаблон класса)